java com orientação a objetos

145

Upload: kevin-santos

Post on 29-Dec-2015

372 views

Category:

Documents


2 download

DESCRIPTION

asasaasasasasasasaa

TRANSCRIPT

JAVA com Orientação a Objetos

�������©©�� ��������������� ������ ��������

����������������������� ����������������������� �� ������������������������������������������ ������!�"#$%���#!&'&#!!(%���)� ��������� ���������*����������+���% � ���� ����� ��������% ���� �,�� ,�� � �� � �-����% � �.����% �����/���0����������%�� �����1���������+�23�%����������%�����������

��������4�� ������1�4�����,�������� ������������ ���5��������,������������ ���������� � ������� �������������� 4�� ��5� )������������� ���� �6������������� �� ���5��������)���

5*���� ������� ������������ ����� � �� � ������ � �� � ����� � ���� � �� � ,���� � � � � ���� � ��� � �� � � � ��/�� �� � ,� � ������ � ��� � ������ � ��7� ���23�% � �� � ����� � � ��� �� � �� � ������� � ��� � � ��% � � � ���� � �� ��� � ������ �+����������� �������������/������������%� �8�/�����7� �������������������������������%�� ����23������/������������������������ �+�23���9�� ,���� )��2�� ��� ����0������������� ������*� ����������:�����

����� �� �!"#�$����

��������������

JAVA com Orientação a Objetos

������6�����;����������:����������������%�'$#'�

#��Informática, 2. Programação de Computador – Programas e Dados���<���� �

��=>�;�!?(@(A@B!!@$'36@1 ���������������������������������������������������$01.642����������������������������������������������������������������������������������������������������������������$$A

������� ��%���� ������� !���&�& ����� ���������' () * ����+��� ��� �� ,������' �, * -����� ��� ./&01/231/ ��� 4.35 ../32))).6 ��7� 4.35 ../32)80)�2���!� !��9!��&�"�&-� :::&!��&�"�&-� /363.

AgradecimentoInicialmente agradeço a Deus por me dar forças e condições de realizar este trabalho. Agradeço ainda a meus amigos, todos esses anos trabalhando com vocês só me fizeram uma pessoa melhor. Em especial, a minha família, a mi-nha querida esposa Fernanda, a meu pai Alexandre, a minha mãe Leonidia, a meus irmãos e a meus queridos sobrinhos. Obrigado a todos pelo apoio tão importante que me fornecem.

IntroduçãoCaro leitor, é um prazer apresentar para vocês a tecnologia Java e os

conceitos vinculados à programação orientada a objetos. A ideia central deste livro é garantir aos estudantes da área de Ciência da Computação e afins uma forma alternativa de conhecer essa tecnologia e o paradigma que atualmente dominam parte do mercado. O livro é resultado de anos de experiência tra-balhando com disciplinas ligadas à área de programação, no qual foram apli-cados conhecimentos da tecnologia Java, assim como a prestação de serviços que envolviam tais elementos. Ao final da leitura deste livro, espera-se que o leitor tenha conhecimento suficiente para desenvolver e entender as aplica-ções que utilizam as diversas características que norteiam a tecnologia Java.

Nos últimos anos, a programação Java tornou-se uma das mais po-pulares do mercado e tem feito com que os profissionais, que dominam seus preceitos, passem a ser mais valorizados e até mesmo disputados por empre-sas, considerando a carência existente para tais nichos de mercado. Tal fatia de mercado, dominada pela tecnologia Java, deve-se em sua maioria às suas potencialidades, uma vez que são aplicações que podem estar presentes em desde eletrodomésticos, aparelhos celulares, carros até as mais simples, tais como as existentes na Web. Assim, a linguagem Java tem características que a tornam diferenciada, sendo de grande importância no que tange a criação de software.

Diante disso, foi montado um roteiro neste livro, no qual se priori-zou garantir ao leitor uma visão ampla de todos os conceitos importantes para sua iniciação na programação com a tecnologia Java. No Capítulo 1, são apresentados os fundamentos da programação com a linguagem Java, consi-derando elementos importantes, como, por exemplo, as palavras reservadas, estrutura básica de um programa Java e as vantagens e desvantagens de uti-lizar a tecnologia mantida atualmente pela Oracle.

No segundo capítulo, começaremos a ver os fundamentos do paradig-ma de programação orientada a objetos, considerando passo a passo cada conceito, fazendo com que o leitor entenda os aspectos básicos e necessários para a continuidade no aprendizado, como, por exemplo, a ideia de classe e objetos na tecnologia Java. Continuando, no Capítulo 3, são trabalhadas

VI JAVA com Orientação a Objetos

as estruturas mais avançadas da programação orientada a objetos, fazendo com que o leitor consiga dar mais um passo no aprendizado do paradigma e da tecnologia Java, sendo considerados conceitos, tais como construtores, destrutores e outros.

Assim como no Capítulo 3, no Capítulo 4 continuaremos a trabalhar com os elementos mais avançados da programação orientada a objetos, tais como os importantíssimos conceitos de herança e polimorfismo, que devem ser vistos e tratados como elementos-chave da tecnologia Java e do paradig-ma de programação orientada a objetos. Claro que devemos lembrar sempre do conceito de portabilidade oriundo da estruturação muito bem pensada da tecnologia Java como um importante diferencial.

Em nosso quinto capítulo, será apresentado a você, leitor, outros ele-mentos da tecnologia Java, no qual iremos lidar com ferramentas úteis para o dia a dia de um programador. Trabalharemos nesse capítulo com bibliote-cas matemáticas, números randômicos ou ainda veremos como lidar com da-tas, manipular strings e assim por diante. Logo, serão consideradas diversas possibilidades e vantagens que podem ser exploradas, o que com certeza irá auxiliar os programadores a dominarem tais conceitos.

O Capítulo 6 tem por objetivo apresentar o trabalho de tratamento de exceções, sendo de extrema importância seu entendimento, já que se trata de um elemento central nas atividades que exigem a manipulação de dados, seja em arquivos texto, seja mesmo em um banco de dados. Este tema é de grande importância, pois a tecnologia Java possibilita, em sua programação, que sejam tratados eventuais problemas ou erros antes que estes venham a realmente ocorrer, permitindo que sejam tomadas as devidas providências para uma autorrecuperação do software durante a execução. Podemos en-xergar isso como uma prevenção para os possíveis erros nos trechos mais suscetíveis a problemas.

Finalizando, em nosso sétimo capítulo, começaremos a trabalhar com a manipulação de arquivos, lidando com o processo de criação, persistência de dados e leitura de dados utilizando classes e interfaces disponibilizadas pela tecnologia Java.

Amigo leitor, em todo o livro tentarei manter uma linguagem mais simples, clara e cotidiana, na qual o principal objetivo e descomplicar o en-tendimento dos diversos conteúdos mencionados. Recomendo que sejam feitos os exemplos disponibilizados, que foram pensados considerando os aspectos que devem acompanhá-lo em sua jornada. Logo, vamos ao que inte-ressa e tenha uma ótima leitura.

Sumário

Capítulo 1 Conceitos básicos da tecnologia Java..........................1

1.1 Fundamentos da tecnologia Java ....................................................11.2 Estrutura e conceitos básicos da programação Java .......................51.3 Entrada de dados ........................................................................... 131.4 Estruturas de controle ................................................................... 151.5 Arrays e matrizes ........................................................................... 211.6 Funções. ......................................................................................... 25

Capítulo 2 Programação orientada a objetos.............................29

2.1 Conceitos da programação orientada a objetos ........................... 302.1.1 Classe .......................................................................................... 322.1.1.1 Qualificadores de acesso ......................................................... 332.1.1.2 Pacotes ..................................................................................... 352.1.1.3 Import ...................................................................................... 362.1.1.4 Comentários ............................................................................ 372.1.2 Atributos ..................................................................................... 382.1.3 Métodos ...................................................................................... 392.1.3.1 Identificador this ..................................................................... 402.1.4 Mensagem e modularização de código ...................................... 412.1.5 Objeto ou instanciação ............................................................... 44

Capítulo 3 Construtores, destrutores e encapsulamento............51

3.1 Construtores .................................................................................. 513.2 Destrutores e Garbage Collector (Coletor de Lixo) ...................... 543.2.1 Garbage Collector ....................................................................... 553.3 Encapsulamento ............................................................................ 56

VIII JAVA com Orientação a Objetos

Capítulo 4 Herança, polimorfismo e interface...........................63

4.1 Herança .......................................................................................... 634.2 Polimorfismo ................................................................................. 694.2.1 Sobrecarga .................................................................................. 704.2.2 Cast ............................................................................................. 714.2.3 instanceof ................................................................................... 734.2.4 Sobrecarga de construtores ....................................................... 744.2.5 Redefinição ................................................................................. 744.3 Interface ......................................................................................... 764.3.1 Herança múltipla ........................................................................ 83

Capítulo 5 Ferramentas úteis para o dia a dia............................85

5.1 Manipulação de strings ................................................................. 855.1.1 Construtores da classe String .................................................... 865.1.2 Outros métodos .......................................................................... 865.2 Data e hora ..................................................................................... 885.3 Operações matemáticas ................................................................ 935.4 Trabalho com vetores especiais .................................................... 955.4.1 Classe Vector............................................................................... 965.4.2 Classe HashMap ......................................................................... 985.4.3 Classe Arrays .............................................................................. 99

Capítulo 6 Tratamento de exceções e entrada de dados............101

6.1 Tratadores de exceções ................................................................ 1026.1.1 Throws ....................................................................................... 1066.2 Entrada de dados ......................................................................... 107

Sumário IX

Capítulo 7 Manipulação de arquivos de texto ..........................111

7.1 Arquivos ....................................................................................... 1117.2 Entradas ....................................................................................... 1127.3 Saídas ........................................................................................... 1147.4 Streams ........................................................................................ 1167.5 Acessos aleatórios em arquivos .................................................. 118

Referências Bibliográficas................121

Apêndice I Instalação do Sdk e Configuração das Variáveis de Ambiente (Windows Xp) .................................................................................... 123

Apêndice II JAVADOC ........................................................................................... 129

Capítulo 1Conceitos básicos da tecnologia Java

Quando falamos em programação, não há como deixar de vislumbrar tal atividade como sendo um elemento central na vida de um profissional ligado à área de Ciência da Computação e afins. No cotidiano, o mínimo que se espera de um profissional de TI é que este domine os elementos e os con-ceitos básicos, aplicados a uma determinada linguagem de programação.

O mercado atualmente oferta uma infinidade de possibilidades de linguagens de programação para a construção de softwares, indo das mais complexas e trabalhosas até as mais simples. Existem, entre essas linguagens de programação, várias que são bem aceitas no mercado, que consideram obviamente variáveis estratégicas, tais como preço, velocidade da curva de aprendizagem e desenvolvimento. Entre tais, a linguagem e a plataforma de desenvolvimento de aplicações Java vêm no decorrer dos anos tornado-se uma das mais utilizadas e aceitas no mercado. Isso, graças ao seu potencial tecnológico combinado ao paradigma de orientações a objetos, além de considerar os custos envolvidos.

O Java é uma tecnologia que foi originalmente desenvolvida pela Sun Microsystem em meados de 1995, sendo regida pela GPL (General Public License). A Oracle Corporation adquiriu todos os direitos pela Sun e obvia-mente, também sobre a tecnologia Java. Para a maioria dos autores e desen-volvedores, a tecnologia Java pode ser definida como:

“simples, distribuída, interpretada, robusta, segura, de arquitetura neutra, portátil, multifunções e dinâmica“.

Ao considerar tais perspectivas, o objetivo deste capítulo é apresentar e preparar o leitor para compreender e aplicar os fundamentos básicos da tec-nologia Java. Estes são úteis e de extrema importância para a compreensão dos demais conceitos vinculados à plataforma de desenvolvimento mantida pela Oracle e que serão considerados nos próximos capítulos de nosso livro.

1.1 Fundamentos da tecnologia Java

A maioria dos autores restringe-se a citar que o Java consiste em uma

2 JAVA com Orientação a Objetos

linguagem de programação orientada a objetos baseada na sintaxe da lingua-gem de programação C. Porém, podemos ir além disso ao citar que o Java é uma plataforma tecnológica que possui diversas características que o merca-do considera como importante e que devido a isto, tem garantido uma fatia considerável das aplicações desenvolvidas com essa tecnologia. Com certeza, pode-se afirmar que a característica que mais se destaca neste processo e a torna diferenciada diante das demais linguagens consiste na portabilidade dos sistemas desenvolvidos com o Java.

Entende-se portabilidade como, nada mais nada menos, a indepen-dência de plataforma - no caso, o sistema operacional (Windows, Linux, Solaris, MAC OS) e o hardware, no qual os softwares serão executados. Tal característica nasce do fato da estrutura das aplicações desenvolvidas com a tecnologia Java ser inicialmente compilada e depois, interpretada. Indo um pouco mais além no entendimento, o ponto central desse processo esta na geração do bytecode, também conhecido como arquivo com extensão “.class”. Este é obtido ou gerado por meio da compilação do código-fonte dos arqui-vos “java puros” ou de extensão “.java”, que serão interpretados futuramen-te. É importante mencionar que com isso, graças ao fato da tecnologia Java possuir para cada plataforma (sistema operacional + hardware) uma Máqui-na Virtual Java, também conhecida como Java Virtual Machine (JVM), este processo torna todas as aplicações Java portáveis entre si. Assim, quem irá preocupar-se com as especificidades de cada plataforma não é mais o progra-mador, mas sim a JVM fornecida.

Essa máquina virtual é capaz de interpretar os arquivos compilados (“.class”), iniciando a execução do software, independentemente da platafor-ma na qual o programa foi construído. Por exemplo, uma vez compilado nos-so programa utilizando o sistema operacional Windows em uma estrutura de hardware da família x86, caso queiramos que nosso programa rode em uma máquina com o sistema operacional Linux, não será necessário realizar uma nova compilação para este software, como acontece com as outras tecnolo-gias e linguagens de programação. Neste contexto, será apenas necessária a presença da JVM para o Linux instalado, o que hoje é algo natural nas má-quinas comercializadas.

Como o leitor pode reparar, esta característica ímpar só é possível gra-ças à existência da JVM, que é fornecida pela tecnologia Java e na qual cada sistema operacional possui uma específica, distribuída pela mantenedora da tecnologia. A JVM pode ser vista como sendo uma camada intermediária

Capítulo 1 - Conceitos básicos da tecnologia Java 3

entre sua aplicação e a plataforma que executará seu programa. A maioria dos computadores atuais já é vendida com algum tipo de Máquina Virtu-al Java e isso tem garantido uma popularização ainda maior das aplicações Java, o que nos faz crer que, em sua maioria, qualquer aplicação Java funcio-nará corretamente nos computadores obtidos atualmente no mercado. Para uma melhor visualização do processo citado como portabilidade, a Figura 1 demonstra o modelo computacional definido pela tecnologia Java e suas aplicações. Vamos conferir?

Figura 1: Estrutura de compilação e execução de programas no Java.

Como definição, podemos mencionar que um programa Java consis-te em um conjunto de instruções, que a JVM é responsável por interpretar e dessa forma, garantir a independência de plataforma na qual o programa foi construído e será executado. Isto é, basta que haja uma implementação de uma máquina virtual para a plataforma ser utilizada. O termo platafor-ma, como já vimos, normalmente no meio computacional é definido como a combinação de sistema operacional mais hardware. Porém, para a plataforma Java, ela é definida somente com o software, por isso o conceito de máquina virtual.

A plataforma Java possui dois componentes que precisamos conhecer quando a adquirimos, sendo:

4 JAVA com Orientação a Objetos

Máquina Virtual Java (JVM): A máquina imaginária que é implemen-tada por meio da emulação em um software executado em uma máquina real e que fornece as especificações da plataforma de hardware para a qual todo o código Java está compilado. A JVM faz parte do ambiente de execução Java, mais popularmente conhecido como JRE (Java Run-Time Environment);

Interface para Desenvolvimento de Aplicações (API Java): Trata-se das interfaces de desenvolvimento para a utilização na criação de aplicações Java, no caso são as bibliotecas para a criação de programas que a própria lin-guagem Java fornece, disponibilizados por meio do JDK (Java Development Kit) ou como vem sendo disponibilizado nos últimos anos como SDK (Source Development Kit).

Para o desenvolvimento de aplicações Java, é necessário que se tenha instalado no computador o SDK. Desta forma, obtenha uma cópia na página oficial da Oracle e instale em seu computador.

O Apêndice deste livro contém mais informações sobre o processo de instalação do pacote SDK, assim como a confi-guração das variáveis de ambiente necessárias para a correta utilização do conjunto de ferramentas da tecnologia Java.

Após a correta instalação e configuração das variáveis de ambiente do SDK, podemos usar um editor de texto qualquer para a construção do código de nosso programa Java. Porém, existem diversos ambientes de de-senvolvimento, também conhecidos como IDE (Integrated Development Environment), para a programação Java, sendo que os mais utilizados no mercado são: Eclipse, NetBeans e JBuilder.

Como nossa intenção consiste no aprendizado da linguagem Java, não nos apegaremos a nenhuma IDE, o que deixa você, leitor, livre para a uti-lização ou não de uma dessas ferramentas de desenvolvimento, sendo que apenas um editor de texto será suficiente para concluir o aprendizado deste livro.

Um aspecto importante a ser citado aqui é que a linguagem Java pos-sui diferentes tipos de programas, sendo que a classificação é feita por meio da modalidade X localização de execução dos mesmos. Assim, esses progra-mas podem ser definidos como: applications, applets e servlets. Nesta unida-de, somente trabalharemos com as applications no console, ou seja, prompt de comando, seja Windows, seja Linux.

Capítulo 1 - Conceitos básicos da tecnologia Java 5

1.2 Estrutura e conceitos básicos da programação Java

Agora, vamos ao que interessa. Nesta seção do livro, vamos aprender como são construídas as estruturas básicas para os programas escritos na linguagem Java, além de conhecer os conceitos mais básicos da programação com a tecnologia. O primeiro detalhe que deve ser considerado na linguagem consiste no fato de que todo programa Java é uma classe, independentemen-te das três possíveis modalidades dos programas Java citadas anteriormente (Applications, Applets e Servlets). A estrutura básica é sempre a mesma: “uma classe”. Um programa Java é organizado em arquivos de texto com a exten-são “.java” e cada arquivo pode conter várias classes, mas usualmente tere-mos apenas uma. Aqui, temos uma consideração importante e que você não deve esquecer jamais:

O nome do arquivo da classe java deve possuir exata-mente o mesmo nome que foi dado internamente à classe, pois a máquina virtual procura a classe por meio do nome do arquivo.

Uma metodologia que pode auxiliá-lo a entender a tecnologia Java neste momento consiste na utilização de analogias com outras linguagens de programação, das quais você já tenha conhecimento e domínio. Então, vamos a elas! Se fôssemos realizar uma comparação básica, poderíamos dizer que as classes no Java podem ser comparadas às famosas units do Pascal. Já para os adeptos do C e C++, a estrutura de nossos programas praticamente será a mesma, uma vez que a tecnologia Java está baseada em tais lingua-gens. Ainda, veremos mais à frente em nossos capítulos que os atributos no Java são como as variáveis existentes em Pascal e C, e os métodos das classes Java seriam os procedimentos e as funções da linguagem C e Pascal. Vários destes aspectos citados serão considerados quando estivermos tratando do conceito de orientação a objetos.

Outro detalhe a ser considerado é a definição de blocos de código que, no Java, são definidos com a utilização de “{“ e “}”, assemelhando-se assim ao C ou C++, diferentemente dos elementos em Pascal, que utilizam no caso, “BEGIN” e “END”. Por enquanto, preocupe-se apenas em entender como os blocos são definidos, sendo de extrema importância para começarmos a

6 JAVA com Orientação a Objetos

entender os conceitos fundamentais para a construção de programas simples com a tecnologia Java.

Então, diante disso, vamos ao que interessa. Chegou a hora de desen-volvermos nosso primeiro programa em Java. Transcreva o conteúdo abaixo para um editor de texto simples, tal como o ‘notepad’ do Windows ou mesmo o ‘Vi’ do Linux. Por enquanto, siga o exemplo conforme é apresentado, digi-tando como pode ser observado na primeira coluna, visto que a linguagem Java é case sensitive, ou seja, existem diferenças entre as letras maiúsculas e minúsculas em sua compilação e interpretação. A seguir, faremos uma análi-se do que foi feito em nosso primeiro programa.

//Classe PrimeiroPrograma.java

class PrimeiroPrograma{

public static void main (String arg []){

System.out.println(“Olá leitor”);

}

}

Agora que você já construiu seu primeiro programa em Java e consi-derando o que já foi citado anteriormente neste capítulo, salve seu programa lembrando que o nome do arquivo Java deve ser necessariamente igual ao nome de declaração da classe - no caso específico, o arquivo deve ser salvo como “PrimeiroPrograma.java”. Salve o arquivo tomando o cuidado neces-sário para assegurar que a extensão “.java” seja garantida por seu editor de textos, uma vez que eles podem manter a extensão “.txt” e isso impedirá a compilação e a interpretação de seu programa.

Feito isso, vamos à explicação de nosso programa, entendendo o có-digo apresentado. Para que você tenha um programa executável construído com a linguagem Java, sua classe deve sempre possuir um método específi-co, que caracteriza a classe como uma aplicação que a Máquina Virtual Java deverá interpretar no momento da execução do programa. Todo programa/classe Java que possuir a função executável ou, como veremos nos capítulos seguintes, o método executável com a assinatura “public static void main (String[] args){ }” apresentada na linha 3 de nosso código anterior, será considerado um programa executável pela JVM.

Capítulo 1 - Conceitos básicos da tecnologia Java 7

Logo, este trecho será executado automaticamente quando for encon-trado no programa submetido à maquina virtual. Um detalhe importante que deve ser comentado nesse trecho trata-se do vetor (array) “String[] args”. Esse trecho presente na assinatura de nossa função executável pode conter parâmetros, que foram passados pela linha de comando na execução de nosso programa. Demonstraremos isso a seguir.

Outro detalhe a ser destacado e que você deve reparar no código apre-sentado, está no fato de que, por convenção, ou seja, algo aceito por todos os programadores Java, os nomes das classes no Java são sempre iniciados com letra maiúscula e, caso venham a ser compostos, cada nova palavra será iniciada novamente com uma letra maiúscula, definindo seu início. Note que isso é feito em nosso código anterior e, diante disso, passe a adotar em seus programas Java. Na quarta linha de nosso primeiro programa, é apresentada a linha System.out.println(“Olá leitor”);, que nada mais faz do que reali-zar a impressão em console. Esse comando informa ao sistema (System) que será realizada uma operação de saída (out), sendo que tal operação consiste em uma impressão com quebra de linha (println). Existem outras possibili-dades de realizar a impressão em console Java e estaremos lidando com elas no momento certo. Então, memorize a linha demonstrada, pois sempre ire-mos utilizar essa linha de código quando quisermos realizar a impressão em console em nossos próximos programas.

Certo pessoal, até aqui conseguimos vencer uma parte importante de nosso primeiro capítulo, considerando que os aspectos citados são comuns a qualquer programa Java que você venha a construir de agora em diante. Mas, está faltando visualizarmos o resultado de nosso primeiro programa. Para isso. teremos de compilar e interpretar nosso programa e, logo, necessitamos de outras ferramentas.

Existem dois comandos básicos que a tecnologia Java fornece por meio do JDK para tais funções, sendo: javac e java, respectivamente. Tais comandos só funcionarão em seu prompt de comando, como, por exemplo, o DOS do Windows, depois de definidas as variáveis de ambiente, para que os comandos estejam disponíveis em qualquer caminho de seu sistema opera-cional, sendo:

JAVA_HOME: Deve conter o caminho da pasta, na qual foi instala-do o SDK, ou seja, o local onde possui todas as ferramentas e APIs básicas fornecidas pela tecnologia Java em seu computador;

8 JAVA com Orientação a Objetos

CLASSPATH: Deve conter o caminho no qual estão localizadas as bibliotecas dos programas que você está utilizando. Por padrão, o valor desta variável é apenas “.”, que significa que as bibliote-cas utilizadas estão na mesma pasta da aplicação que você está desenvolvendo. Caso seja necessário, incremente a essa variável os caminhos nos quais existam outras APIs importantes para o desenvolvimento de sua aplicação, que podem ter sido adquiridas na Internet, por exemplo.

Para que você obtenha maiores informações sobre a criação de vari-áveis de ambiente, disponibilizamos, ao final deste livro, no ANEXO I, um tutorial sobre o assunto. Além disso, podem ser encontrados na Internet di-versos tutoriais sobre o assunto, sendo que sempre devemos levar em con-sideração o sistema operacional a ser utilizado no momento do desenvolvi-mento e da configuração.

Uma vez que o JDK está instalado corretamente e foram definidas as variáveis de ambiente, estamos prontos para compilar e executar nosso primeiro programa. Assim, digite os comandos apresentados abaixo em um prompt de comando do seu sistema operacional, considerando que no prompt, devemos estar no diretório no qual são mantidas nossas classes. Em nosso exemplo, a classe PrimeiroPrograma.java está no diretório c:/>programas.

javac PrimeiroPrograma.java

java PrimeiroPrograma

O primeiro comando apresentado consiste no javac que irá realizar a compilação de sua classe. Já o segundo comando apresentado, java, irá reali-zar a interpretação do bytecode gerado por meio da compilação, conforme a estrutura apresentada na Figura 1.

Certo! Se tudo ocorreu conforme o esperado, será impresso o texto “Olá leitor”, como é apresentado na imagem a seguir.

Capítulo 1 - Conceitos básicos da tecnologia Java 9

Caso o leitor tenha dúvidas sobre como realizar a navegação nos di-retórios de seu computador, indicamos a leitura de qualquer tutorial que auxilie na manipulação de comandos na linha de comando de seu sistema operacional.

Mas, outro ponto importante na construção de uma aplicação no Java, ou seja, na construção das classes e que deve ser considerado para darmos um passo adiante em nosso aprendizado consiste na definição das variáveis de uma classe Java. Em muitos momentos, conforme já mencionamos, as variáveis na linguagem Java aparecerão nos textos, livros e tutoriais, sendo tratadas como atributos. Logo, qual a diferença entre atributos e variáveis?

A diferença entre eles é que um atributo está intrinsecamente ligado às características da classe, ou seja, descreve algo ligado ao contexto ou à ideia central à qual a classe está relacionada ou preocupa-se em descrever. Um exemplo seria um atributo para manter os dados de RG de uma pessoa. Já as variáveis não precisam ser aplicadas necessariamente a um contexto da classe, como, por exemplo, em uma variável auxiliar para o comando de re-petição FOR ou mesmo uma constante. Por enquanto, não se preocupe com isso, pois no decorrer da disciplina, essa diferença se tornará mais clara e logo você saberá diferenciar tais elementos de programação com base nos paradigmas da orientação a objetos.

Em continuidade ao nosso aprendizado sobre os conceitos básicos da tecnologia Java, vamos por a mão na massa e criar nosso segundo progra-ma, utilizando o armazenamento em memória com variáveis. Transcreva o código a seguir para um editor de texto, assim como fizemos em nosso pri-meiro programa. Depois disso, compile e execute-o por meio dos comandos javac e java, respectivamente, em um prompt de comando de seu sistema

10 JAVA com Orientação a Objetos

operacional, conforme realizado no exemplo anterior. Não se esqueça: Para que você consiga executar tais comandos seguido do nome de seu programa, aqui SegundoPrograma.java, você deve estar localizado no diretório no qual a classe se encontra, no caso onde foi salva. Fique atento também ao fato mencionado de que o nome de nosso arquivo Java deve ser igual ao da classe - neste exemplo, nosso arquivo Java deve ser nomeado como SegundoPro-grama.java.

// SegundoPrograma.java

class SegundoPrograma{

public static void main (String arg []){

int a = 5;

a = 5+10;

System.out.println(“O valor é:”+a);

}

}

No código de nosso segundo programa, começamos a manipular o ar-mazenamento na memória volátil, ou seja, a criação de variáveis. No progra-ma, foi inicialmente criada uma variável do tipo inteiro ‘a’, que recebe uma atribuição de valor, no caso o valor ‘5’. Depois, na quarta linha de nosso se-gundo programa, é feita uma operação cujo resultado é armazenado na mes-ma variável ‘a’, que é impressa na linha seguinte. Note que, em regra, quando se quer definir variáveis, constantes e mesmo atributos no Java, como ve-remos nos conceitos de orientação a objetos, em primeiro lugar você deve informar o tipo de dado que será mantido, no caso String, int ou qualquer outro tipo de dados, sendo ele primitivo ou não. Depois, é dado o nome de acesso à variável e finalmente, atribuímos um valor inicial ou não, conforme é apresentado a seguir.

Tipo variável = ValorInicial;final tipo CONSTANTE = Valor;

Capítulo 1 - Conceitos básicos da tecnologia Java 11

Na segunda linha de nossa caixa anterior, a palavra reservada final determina que tal variável não sofrerá alterações, sendo mantido o valor atri-buído no momento de sua declaração, consistindo assim em uma constante para todo o programa, enquanto este estiver em execução. Outro detalhe importante que você deve saber e nunca mais esquecer é que o Java é uma linguagem de programação fortemente orientada a objetos e com exceção dos tipos primitivos, “qualquer” coisa no Java consiste em uma classe/ob-jeto. Devemos destacar que existem várias palavras que são reservadas pela linguagem Java e elas não podem ser utilizadas em vários momentos em seu programa, como, por exemplo, na definição de nome dos atributos, classes ou outros elementos. Tais palavras reservadas são apresentadas na Tabela 1 a seguir.

Tabela 1. Palavras reservadas.

abstract double int strictfp

boolean else interface super

break extends long switch

byte ���� native synchronized

case ������ new this

catch ��� package throw

char for private throws

class goto protected transient

const if public try

continue implements return void

default import short volatile

do instanceof static while

Várias dessas palavras reservadas são elementos naturais em outras lingua-gens de programação, principalmente na linguagem C. Assim, o leitor que já possui algum domínio do C ou C++, não terá dificuldades com a manipulação das palavras reservadas no Java.

Outro ponto importante no Java é que devem ser considerados, uma vez que são extremamente necessários, os operadores matemáticos. No caso, utilizamos os operadores +, -, * e / para realizarmos as operações matemáti-cas básicas, ou seja, soma, subtração, multiplicação e divisão, respectivamente. No Capítulo 5, iremos trabalhar com a API Math, que possibilitará a você realizar operações matemáticas mais complexas. Devemos ainda considerar

12 JAVA com Orientação a Objetos

outros operadores que são de suma importância para a linguagem Java, es-tando relacionados principalmente ao processo lógico dentro de nossos pro-gramas, como no caso dos testes condicionais, sendo que os mais utilizados são listados no quadro da Tabela 2.

Tabela 2. Operadores no Java.

OPERADORES DESCRIÇÃO

== Igualdade

!= Diferente

> Maior

< Menor

>= Maior igual

<= Menor igual

! Negação

&& E lógico

|| Ou lógico

Entre as várias considerações que podem ser feitas quanto ao uso dos operadores, devemos destacar ainda a outra funcionalidade atribuída ao ope-rador “+”, que consiste na concatenação de Strings, como pode ser observado em nosso próximo exemplo. Conforme mencionado anteriormente e como pode ser vislumbrado na Tabela 1, uma String não é um tipo primitivo, mas sim uma classe. Logo, você deve estar perguntando-se: “Então, qual a dife-rença entre um tipo primitivo e uma classe”? Existem várias diferenças que poderiam ser citadas, mas como diversas delas estão relacionadas ao concei-to de orientação a objetos, do qual ainda não tratamos, vamos prender-nos inicialmente à diferença de que uma classe geralmente agrega funcionalida-des das quais os tipos primitivos não dispõem.

Essas funcionalidades, no caso, são denominadas de métodos e que co-nheceremos mais profundamente no Capitulo 2. Um exemplo que demons-tra essa diferença com a utilização de uma funcionalidade pode ser observa-do no exemplo a seguir, no qual é realizada a conversão de uma String em um inteiro, sendo de extrema importância para os vários programas que iremos construir. Logo, tente memorizar tal funcionalidade da classe Integer.

Capítulo 1 - Conceitos básicos da tecnologia Java 13

// TerceiroPrograma.java

public class TerceiroPrograma {

public static void main(String args[]){

String entrada = “1”;

entrada = entrada+”1”;

Integer numero = Integer.parseInt(entrada);

System.out.println(entrada);

System.out.println(numero);

}

}

Note que no exemplo anterior, é criada uma variável do tipo String de-nominada entrada, que recebe o caractere “1”. Note que não é um número, mas sim um caractere. Em nossa segunda linha do exemplo, o valor existente na variável de entrada é concatenado a um novo caractere, no caso “1”. Note que o resultado dessa operação matematicamente seria o valor 2, mas, no caso, por se tratar de manipulação, em específico uma concatenação, o valor mantido na variável será “11”, pois não estamos lidando com uma operação matemática. Na terceira linha é feita a transformação desse conjunto de ca-racteres em um tipo número, que possibilitará as operações matemáticas. Nas duas últimas linhas do exemplo são realizadas as impressões em console dos valores existentes nas duas variáveis do programa.

1.3 Entrada de dados

Bom pessoal, um importante aspecto de qualquer programa compu-tacional consiste na entrada de dados. Pois bem, a primeira coisa a ser feita é conhecer a classe Scanner do pacote java.util. A classe Scanner possibilita que seja realizada a leitura dos dados procedentes tanto do teclado quanto de outras fontes como arquivos de texto. A Scanner passou a ser disponibilizada a partir da distribuição Java 5, na qual se buscou simplificar todo o traba-lho com a manipulação de dados oriundos de fontes de dados, no caso as streams vindas do sistema (System.in) ou mesmo de arquivos de texto. Pois bem, nada como um exemplo para que possamos memorizar todos os con-ceitos e detalhes vinculados à classe Scanner. Assim, transcreva o código a seguir e execute, observando a utilização de nossa nova funcionalidade.

14 JAVA com Orientação a Objetos

//QuartoPrograma.java

import java.util.Scanner;

class QuartoPrograma{

public static void main(String[] arg){

Scanner entrada = new Scanner(System.in);

System.out.println(“Digite um numero “);

//lendo o número digitado no teclado

int valor = entrada.nextInt();

System.out.println(“o numero digitado “ + valor);

}

}

Repare que em nosso exemplo anterior, surgiu um novo elemento que está relacionado à importação de uma classe para sua utilização. Este concei-to ficará mais claro em nosso próximo capítulo quando estivermos falando sobre os conceitos relacionados à mensagem entre as classes por meio de métodos. Mas, voltando ao exemplo, repare que na quarta linha é criada uma variável denominada entrada do tipo Scanner, que é inicializada ‘escutando’ as entradas do sistema (System.in). Repare que na sexta linha de nosso pro-grama, por meio da função ou do método nextInt( ) da variável de entrada, o valor digitado pelo usuário será atribuído à variável valor, que será impressa na linha seguinte. No momento da execução do programa, você irá reparar que logo após ser impressa a mensagem solicitando que o usuário digite um número, o programa aguardará a entrada do valor. Isso se deve às caracterís-ticas do método nextInt( ) da classe Scanner.

Um ponto importante a ser citado está no fato de que, assim como no caso das impressões no console, existem outras possibilidades para rea-lizar a entrada de dados no Java, porém, com certeza, a utilização da classe Scanner é a mais simples. Portanto, em nossos exemplos iniciais, a utilização da classe Scanner será o suficiente até que conheçamos as outras possibilida-des e você escolha qual a mais adequada para seus programas.

Capítulo 1 - Conceitos básicos da tecnologia Java 15

1.4 Estruturas de controle

Certo pessoal, chegamos a um ponto importante de sua leitura, no qual iremos aprender a trabalhar com uma das características mais impor-tantes em um programa, que consiste nas estruturas de controle. Agora, comentaremos sobre os famosos if/else, switch, while, do-while e for. Po-demos mais uma vez considerar a relação de analogia para entender estes co-mandos. Essencialmente, a única diferença desses comandos no Java para a programação em Pascal está nos indicadores de bloco “{” e “}”, sendo, porém, semelhantes em C ou C++.

Então, vamos trabalhar com cada um deles. O primeiro consiste no comando de seleção if que possibilita que um programa analise se uma ex-pressão lógica é verdadeira ou falsa e a partir disto, direcione a execução de seu programa. A estrutura do if trabalha com a perspectiva de acontecimen-tos, logo, realiza o que sua tradução do inglês, que é “Se”, se propõe. Sendo mais detalhista, trata-se de uma estrutura na qual, “Se” a expressão lógica do comando for verdadeira, a sequência natural do if será executada. Porém, “Se” a expressão lógica for falsa, surgirá um novo elemento na estrutura, que consiste na cláusula else (então). Essa cláusula será executada na sequência do if, obviamente se ela tiver sido implementada.

if (expressão_lógica){

Sequência 1;

}else{

Sequência 2;

}

Para que não existam dúvidas, vamos a um pequeno exemplo de fixa-ção dos conceitos do comando de seleção if/else.

16 JAVA com Orientação a Objetos

//Classe ExemploIf.java

class ExemploIf{

public static void main (String[] args){

if (args.length > 0){

System.out.println(“Dentro do if”);

}else{

System.out.println(“Dentro do else”);

}

}

}

Assim como fizemos em nossos exemplos anteriores, salve sua classe com o nome “ExemploIf.java” e utilize os comandos javac e java, respectiva-mente, para a compilação e a execução de seu programa, conforme é apresen-tado na figura a seguir.

Repare que em nossa figura anterior, junto ao comando java e ao nome da classe, consta um conjunto de valores “Teste do if/else”. Estes, por sua vez, são os argumentos passados para o programa durante a execução, que podem ser acessados por meio do vetor de String “args”, presente na assi-natura do método principal void main. No exemplo apresentado no código java, o código dentro do bloco definido pela cláusula if só será realizado caso, pelo menos, um argumento seja passado no momento da execução do pro-grama, do contrário, o vetor args estará vazio e o bloco da cláusula else será executado.

Capítulo 1 - Conceitos básicos da tecnologia Java 17

Outra interessante estrutura de seleção que deve ser mencionada con-siste na cláusula switch. A switch é equivalente de maneira lógica a um con-junto de cláusulas if organizadas de forma encadeada e isso é usualmente mais eficiente durante uma execução de um programa. A expressão utiliza-da pelo switch deve retornar necessariamente um resultado ordinal, ou seja, classificado em um dos possíveis blocos da cláusula, mais conhecidos como “case”. As diretivas encontradas a partir do caso escolhido são executadas até o final da cláusula switch ou até uma ordem de “break” que encerra a cláusula. Se o valor a ser testado não possuir um caso específico, então será executada a diretiva default, que é opcional, sendo colocada ao final da cláusula switch, após todos os casos de classificação possíveis. Assim, para um melhor enten-dimento do mencionado, vamos a mais um exemplo.

/Classe ExemploSwitch.java

class ExemploSwitch{

public static void main (String args[]){

switch(args[0].charAt(0)) {

case ‘A’:System.out.println(“Vogal A”);

break;

case ‘E’:System.out.println(“Vogal E”);

break;

default:System.out.println(“Não é vogal”);

}

}

}

Repare que, em nosso exemplo, trabalhamos mais uma vez com a uti-lização do vetor args, ao qual os valores são passados durante a execução, conforme feito no exemplo para a cláusula if. Aqui, nosso programa faz uma verificação se a vogal presente na primeira posição do vetor é a vogal ‘A’ ou ‘E’, ou seja, realiza a classificação dos valores testados. É interessante men-cionarmos a existência da diretiva default no exemplo, que será executada se nenhum dos casos for realizado. Então, salve seu programa e execute, con-forme apresentado a seguir.

18 JAVA com Orientação a Objetos

Veja que neste exemplo, fizemos uso mais uma vez dos argumentos para passar valores para que sejam verificados em nosso programa, em espe-cífico a vogal ‘A’.

Prosseguindo, outra estrutura a ser mencionada no Java é a estrutura de repetição condicional while. O while consiste em uma cláusula na qual seu bloco será executado durante ou ‘ENQUANTO’ a expressão lógica a ser testa-da for verdadeira. A execução do bloco só será realizada desde que a expres-são lógica analisada seja verdadeira. A síntaxe para a estrutura de repetição while é descrita a seguir.

while ( expressão lógica ){

Sequência;

}

Assim, mais uma vez iremos recorrer a um exemplo para a fixação des-ta estrutura de controle de fluxo. No programa abaixo, iremos imprimir os valores menores que o passado no argumento durante a execução para nosso programa.

//Classe ExemploWhile.java

class ExemploWhile{

public static void main (String args[]){

int j = 10;

Capítulo 1 - Conceitos básicos da tecnologia Java 19

while (j > Integer.parseInt(args[0])){

System.out.println(«»+j);

j--;

}

}

}

Outra possibilidade na linguagem de programação Java para a estru-tura de repetição while consiste na estrutura do-while, que pode ser utilizada como uma condição ao final do loop. Essa estrutura está intrinsecamente li-gada à tradução dos termos, que é: “faça/enquanto”. Isso faz com que tenha-mos a garantia de que o bloco de código definido será executado ao menos uma vez. No caso, ambas as estruturas apresentadas, while e do-while são repetições baseadas em condições lógicas. Observe a seguir a síntaxe da es-trutura do-while.

do{

Sequência;

}

while (expressão_lógica);

Vamos brincar com a estrutura do-while? Então, transcreva o código abaixo, compile e execute-o.

//ExemploDoWhile.java

public class ExemploDoWhile {

public static void main (String args[]) {

int min, max;

Scanner entradas = new Scanner(System.in);

System.out.print(“Digite o valor minimo:”);

min = entradas.nextInt();

System.out.print(“Digite o valor maximo:”);

max = entradas.nextInt();

do {

System.out.println(“” + min + “ < “ + max);

min++;

20 JAVA com Orientação a Objetos

max--;

} while (min < max);

System.out.println(“” + min + “ < “ + max +

“ Condicao invalida.”);

}

}

No exemplo, são capturados dois valores vindos do teclado. O mais importante de nosso exemplo está na cláusula do-while, que irá imprimir os valores mínimo e máximo passados, e que serão impressos em tela e decre-mentados, pois fazem parte do bloco “do”, ou seja, o bloco será executado ao menos uma vez. Diante disso, outras impressões só ocorrerão caso a condi-ção existente na diretiva while seja satisfeita. Repare, na figura a seguir, a execução do código proposto.

Porém, existem situações nas quais a repetição necessita ser apenas incremental e decremental, obviamente com uma condição de parada para ambos os casos. Para estes momentos, a estrutura ‘for’ executará a sequência do comando enquanto a expressão lógica for verdadeira. Um fato interessan-te que deve ser comentado sobre essa estrutura é a possibilidade da criação e da inicialização da variável de controle na entrada do comando. Ela será utilizada para o controle da condição, sendo incrementada ou decrementada a cada repetição. A seguir observe a estrutura de repetição ‘for’.

Capítulo 1 - Conceitos básicos da tecnologia Java 21

for(inicialização;

condição;

incremento/decremento){

Sequência;

}

Assim como nos exemplos anteriores, vejamos uma aplicação dessa estrutura.

//Classe ExemploFor.java

class ExemploFor{

public static void main (String args[]){

for (int j=0; j<10; j++){

System.out.println(j);

}

}

}

Repare que na condição a ser satisfeita, foi inicializada uma variável ‘j’ que irá auxiliar no processo de controle com o seu incremento. O mesmo poderia ser feito com o decremento do valor atribuído a ‘j’. No caso, no Java, assim como em C ou C++, o incremento e o decremento podem ser obtidos apenas com a utilização dos comandos ‘j++’ ou ‘j- -’.

1.5 Arrays e matrizes

Agora, em nosso primeiro capítulo, trabalharemos com os arrays ou também conhecidos como vetores e matrizes, que nada mais são que vetores multidimensionais. No caso, os arrays são vistos como estruturas homogêne-as e estáticas, ou seja, mantêm uma estrutura regular que não muda de tama-nho. Logo, o espaço destinado aos armazenamentos de valores, bem como o tipo de dado, é sempre do mesmo tipo do início ao fim da vida do programa.

A primeira posição de um vetor no Java consiste na posição 0. A

22 JAVA com Orientação a Objetos

linguagem disponibiliza diversas propriedades que podem ser úteis na mani-pulação de vetores, uma vez que sua criação é muito simples, como veremos no exemplo a seguir. Uma das propriedades mais importantes de um array é length, que representa o tamanho de seu vetor. Ela se torna útil, pois além de verificar qual o tamanho do vetor, auxilia no acesso a determinadas po-sições, como, por exemplo, a última, que iremos acessar como (length – 1). Mas, vamos ao que realmente interessa, que é conhecer a sintaxe de criação de nossos vetores, bem como verificar sua manipulação. Para isso, o código abaixo demonstra a utilização dos arrays no Java.

//Classe ExemploArray.java

class ExemploArray{

public static void main(String[] args){

int[] vetor = new int[ 10 ];

System.out.println(“Tamanho vetor:”+vetor.

length);

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

vetor[i] = i;

System.out.println(vetor[i]);

}

}

}

Uma vez executado como feito anteriormente, nosso exemplo define um vetor com 10 posições do tipo inteiro. Repare que a definição do espaço de memória para tal vetor depende da utilização da sintaxe ‘[ ]’. Várias podem ser as possibilidades de utilização dos vetores, que, como mencionado, con-sistem em um espaço de memória destinado ao armazenamento de valores durante a execução, auxiliando na organização de nossos programas, como exemplificado com a utilização do comando for.

Eles serão muito úteis em exemplos nos quais não são utilizados con-ceitos relacionados ao banco de dados, pois auxiliam na manutenção dos valores durante a execução. No caso, teremos acesso sempre a uma determi-nada posição, sendo que podemos considerar um vetor como uma linha na qual iremos acessar um endereço de memória mantido em sequência, como demonstrado abaixo.

Capítulo 1 - Conceitos básicos da tecnologia Java 23

0 1 2 3 4 5 6 7 8 910 20 50 70

Assim, se acessarmos o vetor em sua segunda posição, obteremos o va-lor 50. Outro detalhe a ser mencionado na definição de valores para um vetor é que estes podem ser inseridos no vetor no momento da definição de seu tamanho, no momento de sua criação. No caso, execute o exemplo a seguir e observe seu funcionamento.

//Classe NovoVetor.java

class VetorInicializado{

public static void main(String[] args){

double[] nota = {7,8, 8,4, 4,2, 1,8, 6,4};

for(int i=0; i < nota.length-1;i++)

System.out.println(“Valor no vetor:”+nota[i]);

}

}

Repare que no exemplo, o tamanho do vetor apresentado é definido pelos valores que serão armazenados e passados entre { }. No caso, teremos um vetor com 5 posições, no qual sua instanciação é realizada no momento de sua definição com valores do tipo double. Ainda no exemplo anterior, é importante mencionar que devido à nossa estrutura de repetição ‘for’ possuir apenas uma linha definida em seu bloco, no caso a impressão dos valores do vetor, não é necessária a delimitação do bloco de escopo da estrutura com os caracteres “{” “}”.

Certo, mas e quanto às matrizes? Quando falamos sobre matrizes no Java, devemos ter em mente um aspecto importante que, porém, não impedirá ou dificultará seu trabalho. O fato é que a linguagem Java possui somente arrays unidimensionais, sendo que para a criação de arrays multidi-mensionais, ou seja, matrizes, o que podemos fazer é criar ou simular “pseu-domatrizes” por meio da definição de um array de arrays.

24 JAVA com Orientação a Objetos

Obviamente que isso passa de maneira despercebida na construção de suas matrizes, sendo apenas uma estruturação interna da linguagem e que, como mencionado, não irá interferir em seu programa de maneira signifi-cativa. Você deve ter em mente apenas a constante necessidade de duas es-truturas de repetições para percorrer todo o vetor, assim como em qualquer outra linguagem de programação. Para entender melhor o processo, vamos a um exemplo.

//Classe Matrizes.java

class Matrizes{

public static void main(String[] args){

int [][]matriz = new int[2][3];

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

System.out.println(“Linha: “+i);

for(int j=0; j< matriz[i].length; j++){

matriz[i][j]= i+1;

System.out.println(“Valores da coluna”);

System.out.println(matriz[i][j]);

}

}

}

}

Após executar o programa, teremos como resultado a impressão da coluna, da qual cada uma das posições faz parte no momento. Como men-cionamos, são necessárias duas estruturas de repetição para percorrer toda a matriz, lembrando que uma é responsável por fazer referência à linha e a outra estrutura a um novo vetor, no caso, uma pseudocoluna, conforme é impresso no programa anterior.

No Java, existem outras estruturas de vetores que, no caso, são clas-ses que fornecem mais ferramentas e funcionalidades, agregando valor ao programa. Em nosso sexto capítulo, iremos analisar mais e apresentar essas estruturas adicionais para o trabalho com vetores, tais como as classes Array, HashMap e Vector.

Então, para a definição de vetores e matrizes, sempre estaremos envol-vidos em três etapas:

Capítulo 1 - Conceitos básicos da tecnologia Java 25

1-Declaração do vetor ou matriz: Ocorre da mesma forma como em uma variável, porém basta acrescentar antes ou depois da variável um par de colchetes.

Exemplo:

��������

double posicao[][], controle[][];

int []indice;

2- Reservar o espaço de memória: No caso, é necessário definir o tamanho do espaço de memória que será mantido para a estrutura. Para isso, é utilizado o operador new.

Exemplo:

��������������

posicao = new double[10][20];

indice = new int[5];

3- Armazenar valores nas posições: Para armazenar um valor ou informação em um dos elementos do vetor ou matriz, é necessário informar o índice, ou seja, o local no qual iremos manter os dados.

Exemplo:

nota[3] = 7.8;

posição[4][6] = 3365;

double[] nota = {7,8, 8,4, 4,2, 1,8, 6,4};

A manipulação de vetores e matrizes é essencial para o trabalho com as estruturas de dados. Diante disso, fica como sugestão que seja dada uma especial atenção ao trabalho com vetores e matrizes, refazendo os exemplos sugeridos e memorizando sua sintaxe.

1.6 Funções

Caro leitor, chegamos ao último tema que será analisado neste capítu-lo, que se trata do trabalho com funções. Assim como nas demais linguagens, uma função consiste em uma rotina ou sub-rotina automatizada. As funções

26 JAVA com Orientação a Objetos

são interessantes para as atividades que serão utilizadas rotineiramente, ou seja, que se repetirão várias vezes e com isso, evitam que tenhamos de reim-plementar tal trecho a cada momento de necessidade. Resumidamente, sem-pre que se quiser usar um mesmo trecho de código que realiza uma tarefa específica repetidamente, o melhor a fazer é criar uma função.

O entendimento deste conceito é primordial para que, em nosso pró-ximo capítulo, possamos lidar com o conceito de métodos. O primeiro passo para criar uma função gira em torno do fato de que a função deve ser sempre global, ou seja, deve ser enxergada por todo o código da classe e para tanto, também deve ser estática, sendo definida pela palavra reservada static.

A palavra reservada static é responsável por garantir que ao ser reali-zada a execução de uma instância da classe mais de uma vez, somente have-rá uma única referência para determinada variável ou função existente na memória em seu computador. Ou seja, ao declarar uma função como static, todas as instâncias de uma determinada classe irão acessar e compartilhar o mesmo endereço de memória da função. Outro detalhe ao qual devemos ficar atentos é que ao declararmos algum trecho, variável ou função como static, isso nos permitirá que sejam acessados diretamente sem a necessidade de criar uma instância da classe. Esses conceitos ficarão mais claros ao traba-lharmos com a orientação a objetos, porém é importante saber que existem diversos padrões de projetos que fazem referência à utilização da palavra re-servada static, como, por exemplo, o Singleton.

As funções podem ser tanto sem argumentos quanto parametrizadas, porém a estrutura padrão que deve ser digitada dentro da classe, mas fora da função main, como é apresentada a seguir.

static void nomeDaFunção(lista de parametros){

// código da função

}

Em nosso exemplo, a estrutura apresentada faz referência a uma lista de parâmetros, que pode ou não ser declarada. Assim, como mencionado, existem funções nas quais não existem argumentos, mas necessariamente devem existir os parênteses. Para ter uma melhor fixação da sintaxe, vamos a um exemplo da utilização de funções. Digite o código a seguir e verifique seu funcionamento, assim como nos demais exemplos averiguados até aqui.

Capítulo 1 - Conceitos básicos da tecnologia Java 27

// Classe ExemploFuncao.java

public class ExemploFuncao{

public static void mostrarMensagem() {

System.out.println(“Chamei minha função”);

}

public static void main(String[] args) {

// chamando a função dentro do

// programa principal

mostrarMensagem();

}

}

Em nosso exemplo, foi criada uma função chamada mostrarMensa-gem( ), que apenas imprime na tela. Nossa função é chamada dentro do mé-todo principal main( ), ou seja, poderíamos realizar a chamada quantas ve-zes fossem necessárias sem ter de reescrever todo o código novamente. Este exemplo é um bom começo para o entendimento da ideia de mensagens, mas isso é um assunto para o nosso próximo capítulo. É importante mencionar que a ideia de função em java muitas vezes é confundida com o conceito de métodos, sendo que iremos saber mais sobre eles em nosso segundo capítulo

Bom pessoal, assim finalizamos nosso primeiro capitulo e espero que todos tenham assimilado, aprendido e gostado do fascinante e, ao mes-mo tempo, importante mundo Java. Um detalhe que deve ser mencionado e deve fazer parte de sua rotina como programador é que a atividade de pro-gramação torna-se cada vez mais clara com a prática. Desta forma, sempre que possível, refaça todos os exemplos sugeridos neste capitulo. Nos vemos no próximo capítulo.

Capítulo 2 Programação orientada a objetos

A tecnologia Java ganhou espaço nos últimos anos considerando di-versos aspectos. Vários deles já comentamos, como, por exemplo, a ideia de máquina virtual que possibilita a portabilidade entre os programas desen-volvidos com o Java ou mesmo o fato da tecnologia Java ser regida pela GPL. Porém, outro aspecto deve ser mencionado neste contexto. Ele consiste no fato da linguagem Java trabalhar sobre os conceitos oriundos do paradigma da programação orientação a objetos. Neste capítulo, trabalharemos com os conceitos básicos relacionados a este paradigma de programação, obviamen-te baseados na tecnologia Java. Fica como dica que é muito importante que os temas abordados em nosso primeiro capítulo tenham sido assimilados de maneira satisfatória, garantindo assim um melhor aproveitamento dos tópicos que virão a ser tratados não só neste capítulo, como nos seguintes também.

Certo! Vamos ao que realmente interessa. O paradigma de programa-ção orientada a objetos trata de uma forma diferente o enfoque até então trabalhado na maioria das linguagens de programa, que se sustentavam no paradigma de programação estruturada. A ideia por trás do paradigma da programação orientada a objetos baseia-se em uma contextualização mais humana e próxima da realidade, isso considerando que quase tudo o que te-mos e lidamos em nosso dia a dia são objetos. Por exemplo, o carro que você anda, a casa onde você mora.

Poderíamos, então, imaginar que até mesmo as pessoas, animais e qualquer outro tipo de entidade podem ser vistos grosseiramente como ob-jetos. Claro que existem situações nas quais esses “objetos” podem não ser concretos e palpáveis, tal como o veículo que mencionamos, mas no caso abs-trato, como, por exemplo, os softbots (robôs de software), também podemos imaginar que eles existem e possuem elementos que os diferenciam, assim como atitudes e funções que possibilitam que possamos imaginar que estes podem servir de modelos computacionais.

O paradigma de programação orientada a objetos é relativamente novo na concepção e na implementação de sistemas de software, considerado

30 JAVA com Orientação a Objetos

os demais disponíveis no mercado. Vários são os benefícios que podem ser vislumbrados com a utilização desse paradigma, entre eles estão o aumento da produtividade de programadores por meio de uma maior expansibilidade e a reutilização de código, ou mesmo o fato de controlar a complexidade e os custos com a manutenção do software.

Neste caso, o objetivo central da orientação a objetos na criação de programas computacionais é permitir que os programas possam ser desen-volvidos de maneira a espelhar o modo como os objetos são organizados no mundo real, criando a figura de modelos que podem ser reutilizados quantas vezes forem necessárias, bem como criar uma estrutura modular, na qual os problemas possam ser resolvidos sem que o todo seja afetado. Tais benefícios oriundos do paradigma ficarão mais claros com o decorrer da leitura do livro e o conhecimento dos conceitos.

Diante do exposto, caro leitor, é importante que você saiba que a pro-gramação orientada a objetos baseia-se nos seguintes conceitos: classes, atri-butos, métodos e objetos que serão apresentados neste capítulo, além dos construtores, encapsulamento, herança, polimorfismo e interface que serão apresentados em nosso próximo capítulo.

2.1 Conceitos da programação orientada a objetos

Então, vamos lá amigo leitor! Aqui, iremos entender mais a fundo a Programação Orientação a Objetos (POO). Como citado, grande parte de nosso entendimento e relacionamento com as coisas do mundo real se dá através do conceito de objetos concretos ou mesmo abstratos. Observando ainda as coisas e seres que existem, há uma natural tendência a identificar o que é cada uma destas diferentes entidades, um móvel, uma pessoa e assim por diante.

Relembrando um exemplo claro deste fenômeno e que já citamos, olhemos um carro. Logo, algo que se pode ver e reconhecer sua forma, tama-nho, cor e aplicação. Porém, algo que acredito que muitos ainda não imagina-ram é que tais observações podem ser feitas para todos os carros. Esse carro que acabamos de observar não é o único que existe. Inúmeros outros estão disponíveis com as mesmas características, porém sendo objetos completa-mente distintos. O que podemos começar a vislumbrar é que podemos ter computacionalmente uma estrutura que garanta que as informações possam ser mantidas e trabalhadas para inúmeras situações semelhantes.

Capítulo 2 - Programação orientada a objetos 31

Voltemos ao exemplo do carro. Se existem vários carros com as mes-mas características e funcionalidades, é de se imaginar que exista uma for-ma ou molde que garanta que todos saiam iguais, de forma padronizada e serializada. Estes conceitos oriundos da administração foram absorvidos de maneira eficiente pela computação e pelo paradigma da orientação a obje-tos, que adotou a ideia de criação de modelos computacionais que podem ser reutilizados e fazer com que esses elementos se completem, modularizando a programação.

O que temos inicialmente é a ideia de uma modelo, que a qualquer momento podemos dispor de seu uso para criar novos ‘objetos’ de um deter-minado tipo de entidade que será mantida na memória.

É claro que cada objeto no mundo real é único, no caso, ninguém é igual a ninguém. Cada objeto possui uma característica ou mesmo uma fun-ção que o torna único, servindo como uma identidade que o diferencia dos demais, mesmo que sejam do mesmo tipo. Por exemplo, uma pessoa. Todas as pessoas possuem um nome, endereço, trabalho, mas todas são diferentes uma das outras, sendo que cada uma possui sua identidade própria, algo que a torna única e diferenciada. Poderíamos grosseiramente dizer que se trata do RG individual e pessoal de cada objeto. Assim pessoal, além das caracte-rísticas genéricas vinculadas a todas as classes de objetos, existe também a identidade vinculada a cada objeto individualmente.

Por meio dos exemplos citados, podemos descrever informalmente os conceitos fundamentais da programação orientada a objetos, sendo eles:

Classe;Atributos e métodos;Objeto;Referência a Objetos;Construtores;Encapsulamento;Herança;Polimorfismo;Interface.

Como citado no início deste capítulo, iremos concentrar-nos agora apenas nos quatro primeiros conceitos mencionados. Os demais serão apre-sentados nos próximos capítulos.

32 JAVA com Orientação a Objetos

Caro leitor, mas o que você deve ter em mente quando iniciar o estudo sobre os conceitos da orientação a objeto é o fato de que tal paradigma irá auxiliá-lo a entender e visualizar de maneira mais ampla um problema a ser resolvido, conseguindo assim, uma maior independência entre a programa-ção e o modelo do problema a ser trabalhado, o que obviamente irá facilitar possíveis manutenções e reutilizações com uma modularização, como já citei.

2.1.1 Classe

Em nosso primeiro capítulo, já trabalhamos com a criação de classes. Mas, agora, vamos entender sua real contextualização, sendo o conceito pri-mordial para o entendimento da POO. Uma classe é um modelo formado por propriedades ou características, que serão definidas mais à frente como atributos, operações e funcionalidades, que iremos conhecer como métodos e definem o comportamento básico dos objetos oriundos de uma classe.

Podemos imaginar uma classe em seu sentido estrito e epistemoló-gico, ou seja, uma representação genérica de um conjunto de entidades in-dividuais e iguais. Por exemplo, uma classe de alunos, na qual todos são se-melhantes dentro do contexto, com nome, matrícula e assim por diante. Em nosso caso, a classe é a representação comum ou padrão de um conjunto de entidades iguais. As classes são a modelagem das entidades do mundo real de uma forma mais natural computacionalmente, pois estamos acostumados a lidar com “objetos”, que possuem características, “atributos”, funcionalida-des e “métodos”.

Tomemos como exemplo o carro. Este poderia ser definido por uma classe que descreve de maneira comum um conjunto de objetos do tipo car-ro, independentemente de sua marca, cor ou tipo, atendo-se especificamente aos conceitos que, de alguma maneira, descrevem a estrutura de um carro de forma genérica. Então, vamos a um exemplo de uma classe, na qual podemos descrever um conjunto de entidades a partir de um modelo computacional genérico.

// Classe Carro.java

class Carro{

String cor;

String marca;

String modelo;

Capítulo 2 - Programação orientada a objetos 33

void andar(){

System.out.println(“Carro andando”);

}

void parar(){

System.out.println(“Carro parado”);

}

}

Vale a pena novamente mencionar que os nomes das classes devem ser iniciados com letras maiúsculas, diferenciando assim dos atributos e das instâncias de objetos que utilizam letras minúsculas em suas iniciais. Caso o nome seja composto por mais de uma palavra, recomenda-se que as demais palavras também iniciem em letra maiúsculas. Exemplo: Carro, CarroDeCorrida.

Observando o exemplo de classe acima, verifica-se que ela não possui um método principal, sendo assim, ela não retornará nenhuma ação ao ser executada, sendo apenas a descrição de um objeto do mundo real, ou seja, a ideia central e descrevendo o problema a ser implementado. Em nosso caso, descreve uma estrutura para manter os dados e descreve as funcionalidades de um carro como um modelo que será utilizado.

Isso é interessante, pois sempre que quisermos manter informações ou mesmo utilizar suas funcionalidades, não precisaremos implementar no-vamente todo o código, necessitando apenas uma nova instanciação de um objeto da classe ou mesmo sua cópia para outro projeto. De maneira mais formal, podemos então dizer que uma classe é uma abstração que descreve as propriedades relevantes de um conjunto de elementos em termos de sua estrutura, atributos e comportamento - os métodos.

2.1.1.1 Qualificadores de acesso

Outro aspecto interessante e que auxilia em uma programação mais ‘realista’ com a utilização do paradigma orientado a objetos consiste na ideia do qualificador de acesso. Tantos as classes que já conhecemos quanto os atributos e métodos que ainda iremos conhecer fazem uso e estão na maioria das vezes associados ao conceito de qualificador de acesso ou também conhe-cido como especificação de visibilidade.

34 JAVA com Orientação a Objetos

Vamos a uma analogia para tentar entender o conceito de visibilida-de. Você resolve parar um pouco com a leitura de seu livro de programação com Java e resolve dar uma volta de carro. Diante disso, começa a lembrar dos conceitos que leu, rememorando que seu carro é um objeto dentro de uma classe que define todos os aspectos comuns de todos os carros. Mas, ao ligar seu carro, você começa a pensar: “Bom, eu tenho visíveis várias ca-racterísticas e várias funcionalidades, mas existem outras que não consigo enxergar e que tenho certeza que contribuem para o bom funcionamento do veículo, tais como a partida, rotação do motor e assim por diante”. Pois bem, ao considerar esta situação, é possível verificar que, em diversos momentos em nosso cotidiano, existem objetos, características e funcionalidades que estão visíveis e outras não. Logicamente que isso irá depender dos aspectos funcionais e da utilidade de cada objeto.

É aí que entram os especificadores ou os qualificadores de visibilidade. Eles permitem definir quem ou o que pode ser visível ou acessível no mo-mento do desenvolvimento de suas classes. Na maioria das situações, com as quais você irá deparar-se, uma classe fará uso de outras classes e essas devem estar acessíveis por meio da utilização dos qualificadores. Para tanto, deve--se utilizar uma das estruturas apresentadas a seguir. No caso, os tipos de qualificadores básicos são:

Tabela 3. Qualificadores de acesso.

Qualificador Descrição

publicDefine que o conteúdo da classe é público e pode ser utilizado livremente por outras classes do mesmo pacote ou de outro pacote.

protectedDefine que o conteúdo da classe está protegido e que só pode ser utilizado por classes do mesmo pacote.

privateDefine que o conteúdo é privado e só pode ser utilizado inter-namente na própria classe.

Assim, poderíamos enriquecer nosso exemplo da classe carro apresen-tada anteriormente com os qualificadores de visibilidade. Verifique que tanto

Capítulo 2 - Programação orientada a objetos 35

a classe como suas variáveis que descrevem as características e as funções, que descrevem seu comportamento ou funcionalidades, podem fazer uso de tais especificadores.

//Classe Carro.java

public class Carro{

public String cor;

public String marca;

public String modelo;

protected void andar(){

ligar();

System.out.println(“Carro andando”);

}

protected void parar(){

System.out.println(“Carro parado”);

}

private void ligar(){

System.out.println(“Carro ligado”);

}

}

Os qualificadores de visibilidade são essenciais para o conceito de en-capsulamento, com o qual trabalharemos em nosso próximo capítulo. Por pa-drão, quando não declarada a visibilidade de uma classe ou mesmo atributo e método, a máquina virtual Java irá interpretar que tais elementos estarão especificados com o operador protected, ou seja, protegidos e acessíveis ape-nas dentro do pacote do qual fazem parte.

2.1.1.2 Pacotes

Com isso, temos outro conceito que interfere nas classes tanto quan-to a visibilidade. No caso, consiste na ideia de pacotes, declarados no Java como package. A principal função desta diretiva no Java está na organiza-ção das classes e obviamente em sua visualização por outras classes de um projeto. O que podemos então verificar é que o pacote está diretamente

36 JAVA com Orientação a Objetos

relacionado aos qualificadores de visibilidade no acesso a classes, caracterís-ticas e funcionalidades destas.

Ou seja, a utilização da diretiva package na classe indica que todo o conteúdo público (public) pode ser utilizado por outras classes pertencentes ao mesmo pacote ou não. O conteúdo determinado como protegido (protected) na classe pertencente a um pacote só pode ser acessado ou utilizado por ou-tras classes pertencentes ao mesmo pacote e o conteúdo definido como pri-vado (private) só será acessível dentro da própria classe, independentemente do pacote do qual faz parte. Caso o pacote de uma classe não seja informado, essa classe passará a fazer parte do pacote default (src, abreviação de source, traduzindo, fonte).

Do ponto de vista usual, dentro de seu projeto, um pacote de classes Java consiste em um diretório, no qual existem uma ou mais classes, ou seja, é um repositório de classes. Geralmente, colocam-se no mesmo package as classes com o mesmo propósito. Sob certos aspectos, os packages reprodu-zem a ideia de bibliotecas, que podem ser importadas em uma classe Java por meio do comando import.

2.1.1.3 Import

O comando import é responsável por garantir a reutilização e a modu-larização dos programas no Java. Logicamente, tais conceitos são semelhan-tes ao include do C ou C++ e garantem, com os demais conceitos de visibili-dade e pacotes, definições de segurança e organização. Certo pessoal! Diante do exposto até aqui, vamos a um exemplo de uma estrutura padrão de uma classe, considerando todos os conceitos apresentados. Além disso, apresen-taremos um novo elemento da linguagem neste exemplo, que consiste nos comentários.

package local.diretorio;

�����������������������������������������

// atributos da classe

// métodos da classe

}

Capítulo 2 - Programação orientada a objetos 37

Note que a estrutura apresentada apenas define os conceitos já vistos por você nos exemplos anteriores. Porém, deve-se tomar muito cuidado com a manipulação de pacotes e imports, pois podem ocorrer erros de referência, uma vez que as classes e os pacotes não existam.

2.1.1.4 Comentários

Bom pessoal, os comentários são extremamente úteis na linguagem Java. Isso porque não somente permitem os simples comentários, mas ga-nham valor ao considerarmos as possibilidades que a própria máquina vir-tual define para tal elemento. No caso, a tecnologia Java define três tipos de comentários, sendo eles: com uma linha, múltiplas linhas e documentação.

O primeiro, com uma linha, utiliza duas barras (//) para marcar seu início e tudo após as duas barras é considerado um comentário pela JVM. O segundo tipo de comentário utiliza a combinação /* e */ para delimitar as múltiplas linhas de comentários. E o último tipo consiste no comentário de múltiplas linhas, semelhante ao segundo, porém com o propósito de docu-mentar a programação. No Java, recomenda-se como uma boa prática de pro-gramação, que todas as classes sejam documentadas e para isso, a tecnologia Java nos dá uma mãozinha, como pode ser observado no Apêndice II deste livro. Na Tabela 4, é demonstrada a utilização dos comentários apresentados.

Tabela 4. Tipos de comentários

Tipos de comentários

// comentário de uma linha

// tudo após as duas barras é um comentário

/*

comentário

de múltiplas linhas

*/

/** comentário de documentação que também

* podem ter múltiplas linhas

*/

38 JAVA com Orientação a Objetos

Usualmente, o comentário com o objetivo de documentação é posi-cionado antes do elemento a ser documentado, sendo que seu conteúdo é extraído automaticamente pelo utilitário javadoc fornecido com o JDK.

Como mencionado, o apêndice deste livro traz exemplos para a criação da documentação de suas classes, com a utiliza-ção do suporte fornecido pela JVM.

Conforme já citado em nosso capítulo anterior e algumas vezes na se-ção onde definimos as classes, os atributos e os métodos são conceitos que estão intrinsecamente associados à ideia de classe. Então, mãos à obra! Va-mos conhecer um pouco mais sobre esses conceitos.

2.1.2 Atributos

Um atributo nada mais é que uma variável contextualizada, na qual representa uma característica ou uma propriedade da classe de objetos em questão. É uma variável destinada a armazenar informações associadas à classe. Por exemplo, vamos considerar novamente o famoso carro apresenta-do nas seções anteriores. Seja qual for o carro, várias características podem ser elencadas para ele, entre elas, sua marca. Trata-se de uma propriedade comum a todos os carros, pois todo carro possui uma marca ou mesmo uma cor. Assim, é natural que ao definirmos uma classe, por exemplo, CarroDe-Corrida, ela possua um atributo ou no caso, uma variável contextualizada destinada a armazenar sua marca e sua cor.

Podemos definir os atributos como “variáveis da classe que podem ser de tipos primitivos ou de outras classes destinadas a manter os dados dentro de um contexto”. A definição de um atributo dentro de uma classe Java é feita da mesma maneira como em uma declaração de variável, sendo definido o seu tipo e nome, que deve indicar qual seu propósito. Considere o exemplo da classe CarroDeCorrida a seguir.

//Classe CarroDeCorrida.java

package fabrica;

Capítulo 2 - Programação orientada a objetos 39

public class CarroDeCorrida{

public String cor;

public String marca;

}

Mais uma vez, temos de lembrar que, em nossa classe, não existe um método executável, ou seja, o método main( ), sendo que tal classe represen-ta uma descrição de um problema que, no caso, consiste em manter as infor-mações sobre, por exemplo, um carro de corrida durante a execução. Poderí-amos dizer grosseiramente que se trata de um mapeamento das informações a serem mantidas. Mas, de nada valem os atributos sem que estes possam ser trabalhados e transformados. É aí que entram os métodos.

2.1.3 Métodos

Como verificamos no tópico anterior, enquanto os atributos permitem manter dados vinculados e contextualizados aos objetos, ou seja, valores que descrevem as características de um objeto, os métodos são responsáveis por realizar operações sobre os atributos, sendo capazes de especificar ações ou transformações para uma classe de entidades. A ideia central na construção de métodos está relacionada ao fato de conferir um caráter dinâmico aos ob-jetos de uma classe, exibindo um comportamento que transforme e modi-fique seu estado atual. Na maioria das vezes, essa transformação se dá por meio da alteração de valores dos seus atributos, tentando imitar o comporta-mento de um objeto real ou abstrato.

Bom, assim como nos demais conceitos, cada método possui uma assi-natura e corpo definidos por:

qualificador de acesso; tipo de retorno; nome; lista de parâmetros.

Definido o corpo do método, vem seu escopo, que define a implemen-tação à qual o método se propõe, que deve estar entre “{ }”. Apresento a seguir mais um exemplo, além de aproveitá-lo para demonstrar mais um elemento da linguagem Java. Vamos utilizar o exemplo de um caixa eletrônico.

40 JAVA com Orientação a Objetos

//Classe ContaCorrente.java

package banco;

public class ContaCorrente{

!��"����������

private String titular;

!�#���$���%�����&���"����'�

this.saldo -= valor;

return “Saque realizado com sucesso!”;

}

!�#���$���%��!�����&���"����'�

this.saldo = this.saldo + valor;

return “Deposito realizado com sucesso!”;

}

}

Repare que no exemplo, temos dois métodos, sacar e depositar. Por convenção, os métodos sempre devem ser declarados com o verbo no infini-tivo, tal como: desenhar, andar, propor, correr e assim por diante. No caso de nomes compostos, o primeiro nome será no infinitivo e os demais decla-rados normalmente, tal como: gerarDocumentacao( ), depositarDinheiro( ) ou depositarCheque( ). Mas, um elemento deve ter chamado sua atenção no exemplo. No corpo dos métodos pode ser visualizado o identificador this.

2.1.3.1 Identificador this

O identificador this é responsável por fazer referência a um atributo ou método da própria classe. No exemplo apresentado anteriormente, é feita a referência ao atributo saldo. Isso é muito útil, pois é comum que os parâ-metros possuam nomes iguais aos já existentes nos atributos de uma classe, diferenciando-os.

Uma alternativa para a utilização do identificador this é sua definição nas classes Java para a chamada de um método construtor dentro da própria

Capítulo 2 - Programação orientada a objetos 41

classe. Isso é feito por meio do método reservado this( ).É importante que você saiba que todos os conceitos apresentados até

aqui devem ser sempre bem planejados e isso é geralmente feito no momen-to do projeto de suas aplicações. As classes, atributos e métodos podem ser representados de maneira gráfica, o que é extremamente útil para enxergar os possíveis gargalos ou deficiências em sua aplicação.

Para tanto, existem várias notações, geralmente gráficas, para a repre-sentação de classes, atributos e métodos, mas com certeza a mais utilizada comercialmente trata-se da UML (Unified Modeling Language). Não iremos aprofundar-nos quanto à utilização da UML em nosso livro. Fica como suges-tão para o leitor que, como forma de enriquecer sua leitura e aprendizado da programação orientada a objetos, procure conhecer mais sobre tal notação.

2.1.4 Mensagem e modularização de código

Como mencionado no início deste capítulo, um dos pontos-chave da programação orientada a objetos consiste na possibilidade de modularizar o código. Com isso, podemos chegar mais próximo da realidade vivida no coti-diano, bem como possibilitar uma manutenção mais simples. É considerando tais perspectivas que surge um novo conceito relacionado à linguagem Java e ao paradigma de orientação a objetos: a mensagem.

O conceito de mensagem entre as classes Java trabalha com a ideia de que as classes, ou melhor, os objetos ou as instâncias de uma classe podem in-vocar métodos de objetos de outras classes para desempenhar alguma tarefa de maneira a completar sua função e melhor definir o problema. O conceito garante que caso uma classe necessite de um serviço ou funcionalidade, mas a função faça parte de outro contexto, então será necessário apenas utilizar o que é proposto em outra classe, mantendo assim a organização de modo a garantir que todo o código fique em seu devido lugar. Obviamente, isso tor-nará seu código mais inteligível para as possíveis intervenções que venham a ocorrer no futuro, como no caso de uma manutenção.

Dúvidas? Certo, vamos ao já mencionado no exemplo do carro. Imagi-ne que se construa uma classe Carro que possui vários atributos, tais como: cor, marca e modelo. Além disso, na classe sejam definidos os métodos an-dar( ) e parar( ). Pois bem, até aqui nada de novidade. Porém, para que um veículo ande, é necessário que seu motor seja ligado. É aí que entra o conceito de mensagem como uma forma de melhor definir o problema.

42 JAVA com Orientação a Objetos

O correto seria a criação de uma nova classe, que defina a ideia do objeto motor, que teria como atributos características, tais como: potência, ignição e combustível. Além dos atributos, os métodos para a manipulação desses atributos, que seriam, por exemplo, ligar( ) e desligar( ). Desta forma, quando um carro anda, o que é acionado é o motor e para tanto, é ele que deve ter seu estado alterado. O motor, como parte do carro, deve receber uma mensagem oriunda da classe carro que informe tal solicitação, fazendo aces-so ao método ligar( ). Logo, o conceito de mensagem trata da comunicação entre as classes.

Para ter uma melhor fixação, vamos demonstrar tais conceitos da ma-neira como devem ser abordados, criando classes. Aqui, utilizaremos as clas-ses que definem nosso problema e de forma legível para seu entendimento, caro leitor. Então, vamos lá? Transcreva as classes abaixo para um editor de texto. Entretanto, não é necessária a compilação e a execução do programa, já que não temos uma classe principal que garanta uma visualização dos resultados.

// Classe CarroNovo.java

package fabrica;

public class CarroNovo{

// atributos

String cor;

String marca;

String modelo;

Motor novoMotor = new Motor();

// métodos

public void andar() {

novoMotor.ligar();

System.out.println(“ANDANDO”);

}

public void parar() {

novoMotor.desligar();

System.out.println(“PARANDO”);

}

}

Capítulo 2 - Programação orientada a objetos 43

_____________________________________________________

__

// Classe Motor.java

package fabrica;

public class Motor {

// atributos

Boolean ignicao;

String potencia;

String combustível;

// métodos

public void ligar() {

ignicao = true;

System.out.println(“Ligado”);

}

public void desligar() {

ignicao = false;

System.out.println(“Desligado”);

}

}

Neste exemplo, podemos notar que existe um novo elemento na classe CarroNovo, que consiste na utilização de uma INSTÂNCIA da classe Motor. Estarei abordando mais sobre a importância deste conceito na próxima se-ção com o uso da palavra reservada new. Outro exemplo que pode ser útil para o entendimento do conceito de mensagens entre classes é apresentado a seguir.

No próximo exemplo, é implementada uma classe denominada Pro-gramaPrincipal, com um método principal onde se cria uma variável ou para que você vá acostumando-se, um objeto da classe Mensagem que possui o método imprimir( ) acessado durante a execução pela classe ProgramaPrinci-pal. Trata-se de um exemplo sem uma contextualização, mas que é útil para enxergar a divisão de tarefas e a modularização do código com os conceitos da orientação a objetos. Considerando as características do exemplo, pode-mos compilar e executá-lo para a visualização.

44 JAVA com Orientação a Objetos

// Classe ProgramaPrincipal.java

class ProgramaPrincipal{

public static void main (String arg []){

Mensagem m = new Mensagem();

m.imprimir();

}

}

// Classe Mensagem.java

class Mensagem{

public void imprimir(){

System.out.println(“Mensagem”);

}

}

No exemplo, é feita a utilização do método imprimir( ) da classe Men-sagem pela classe ProgramaPrincipal. Ainda no exemplo, é feita novamente a utilização do operador new. Trata-se de mais uma palavra reservada para a tecnologia Java que é responsável pela atribuição de uma instância a um atributo. A ideia de instanciação é essencial para compreendermos todo o paradigma da programação orientada a objetos. Então, vamos conhe-cer o conceito de objeto.

2.1.5 Objeto ou instanciação

Como já deve ter sido percebido, a criação de novos objetos de uma classe se chama instanciação ou simplesmente criação do objeto. O objeto consiste em representar um único exemplar de uma determinada classe. Va-mos voltar ao exemplo do carro. A classe CarroDePasseio representa os atri-butos (características) e os métodos (comportamento) de todos os carros de passeio. Logo, a classe consiste em um modelo para reservar um espaço de memória para manter e transformar os dados. A partir da classe CarroDePas-seio, podemos criar vários objetos, ou seja, várias representações ou instân-cias a partir do mesmo modelo, pertencente à classe. Por exemplo, podemos manter os dados de uma Mercedez, um Gol ou qualquer que seja o carro de passeio. Note, qualquer um dos veículos citados é um exemplar específico da

Capítulo 2 - Programação orientada a objetos 45

classe CarroDePasseio. Cada carro em específico possui características, tais como, cor, tamanho e marca, que o torna único e métodos que definem como ele pode ser ligado, desligado e como deve andar.

Se fôssemos pensar grosseiramente, poderíamos ter uma classe Pes-soa, da qual você, leitor, é um objeto ou uma instância da classe (conjunto) de pessoas. Pensemos, você é único e ninguém é igual ao outro, onde cada um possui características próprias e comportamentos distintos, ou seja, cada um é um objeto diferente pertencente a uma determinada classe.

Pode-se definir um objeto como sendo uma instância de uma classe (grupo) que tem valores próprios para os atributos definidos na classe, tendo uma identidade única, ou seja, sendo único no conjunto de elementos do mesmo tipo. A notação para instanciar um novo objeto utiliza o operador new, destinado à sua criação.

NomeDaClasse nomeDoObjeto = new NomeDaClasse();

Exemplo:CarroDePasseio mercedez = new CarroDePasseio();Mensagem m = new Mensagem();

A primeira coisa que você deve ter reparado é que a declaração de um objeto é realizada de maneira semelhante a dos atributos de uma classe. En-tão, é valido mencionar que as classes podem conter instâncias de outras classes como atributos, com diversos elementos compondo um todo, assim como apresentado na classe Carro e Motor.

Outro exemplo seria a mesma classe carro que pode ter como atributo um proprietário, que pode ser definido como sendo de uma classe Pessoa, como é apresentado no exemplo a seguir. Conforme já visto neste capítulo, o exemplo abaixo apresenta o conceito de importação de outras classes. O código é meramente ilustrativo, não sendo necessária sua execução.

// Classe Carro.java

package concessionaria;

import concessionaria.Pessoa;

public class Carro{

// atributos

46 JAVA com Orientação a Objetos

int velocidadeMaxima = 50;

Pessoa proprietario = new Pessoa();

// métodos

public void mostrarVelocidadeMaxima(){

proprietario.dirigir();

System.out.println(velocidadeMaxima);

}

}

______________________________________________________

// Classe Pessoa.java

package concessionaria;

public class Pessoa{

String nome;

String endereco;

public void dirigir(){

System.out.println(“DIRIGINDO”);

}

}

Mas, quando falamos de objeto, o que realmente está por trás disso é outra importante característica da orientação a objetos, no caso, o reuso do código. Mais uma vez fazendo referência ao exemplo do carro, a mesma clas-se pode ser utilizada para definir vários objetos do mesmo tipo, sendo que somente os dados referentes às características de cada um diferem.

Por exemplo, poderíamos ter um objeto denominado carroDePasseio e outro instanciado com sua referência sendo carroDeCorrida. Ambos podem ser instâncias da classe Carro, sendo que os dois objetos são oriundos da mesma classe, diferenciados apenas pelos valores associados aos atributos que cada um assume. Porém, ambos utilizam o mesmo modelo, mais especi-ficamente, a classe Carro.

Cabe ainda destacar outros detalhes da instanciação de objetos. Ago-ra que já sabemos como os objetos são criados, com a utilização do operador new, é importante entender o que acontece quando criamos esses objetos.

Capítulo 2 - Programação orientada a objetos 47

Quando um objeto é criado por meio do comando new, o que é retornado à variável ou ao atributo, como já vimos, é uma referência. Referência? O que é isso? Vamos à explicação.

Quando um objeto é criado, ele é uma referência ou uma indicação para um determinado espaço de memória reservado, sendo que o nome da variável torna-se apenas uma âncora para o acesso ao espaço de memória no momento da execução de seu programa, no qual estão dispostos nossos atributos e métodos. A ilustração apresentada a seguir torna isto mais claro.

Figura 2. Referência para objetos.

Após a explicação e as considerações feitas sobre o espaço de memória ser o objeto, é necessário também dizer que o operador new não é a única forma de atribuirmos referência a um objeto ou uma instância. Uma maneira de visualizar o objeto como uma referência, no caso uma âncora, é o fato de também se poder fazer a cópia de uma referência de um objeto para outro, com ambos passando a apontar para o mesmo endereço de memória. Se co-piarmos uma referência para outro objeto, ele estará referenciando o mesmo objeto que a instância original está referenciando. Para ter um melhor enten-dimento do que foi dito, observe a Figura 3.

Figura 3. Cópia de referência de objetos.

48 JAVA com Orientação a Objetos

Entendido o conceito, você deve perguntar: Mas, como fica isto em linhas de código no Java? Respondendo ao seu questionamento, observe e transcreva o código na sequência, onde são criadas duas classes que exempli-ficam o explicado. Conforme visto em nosso primeiro capítulo, utilizaremos o método executável main para imprimir os valores que foram referenciados aos atributos das classes.

//Classe Carro.java

package concessionaria;

import concessionaria.Pessoa;

public class Carro{

//atributos

int velocidadeMaxima = 50;

Pessoa proprietario = new Pessoa();

//métodos

public void mostrarVelocidadeMaxima(){

proprietario.dirigir();

System.out.println(velocidadeMaxima);

}

}

___________________________________________________//Classe Pista.java

package concessionaria;

public class Pista{

public static void main(String[] args){

Carro carroDeCorrida = new Carro();

Carro carroDePasseio = new Carro();

carroDeCorrida.velocidadeMaxima = 300;

carroDePasseio.velocidadeMaxima = 60;

carroDeCorrida.mostrarVelocidadeMaxima();

carroDePasseio.mostrarVelocidadeMaxima();

Capítulo 2 - Programação orientada a objetos 49

Carro novoCarro = carroDeCorrida; carroDeCorrida.mostrarVelocidadeMaxima();

carroDePasseio.mostrarVelocidadeMaxima();

novoCarro.mostrarVelocidadeMaxima();

}

}

Entre as diversas linhas que devem ser observadas no código anterior, devemos dar mais importância à linha na qual a instância da classe Carro chamada novoCarro recebe a referência, ou seja, o endereço de memória do objeto carroDeCorrida, observe.

Carro novoCarro = carroDeCorrida;

Os atributos carroDeCorrida e novoCarro fazem referência ao mesmo espaço de memória, pois não foi atribuído um novo espaço de memória para o objeto novoCarro, mas sim, o mesmo espaço ao qual o objeto bolaGrande já fazia referência. Esta é uma característica fundamental da linguagem Java, sendo que sempre são passadas referências no Java, não valores. Tal fato tor-na o trabalho e a manipulação das estruturas de dados com o Java muito simples. Assim, finalizamos nosso segundo capítulo e no próximo, iremos continuar a conhecer outros conceitos vinculados à programação orientada a objetos.

Capítulo 3Construtores, destrutores e encapsulamento

Dando continuidade à nossa análise sobre os conceitos relacionados ao paradigma da programação orientada a objetos, iremos, neste capitulo, descrever e aprender a lidar com três novos e importantes elementos para a tecnologia Java. É importante que os conceitos expostos nos capítulos an-teriores tenham sido compreendidos para ter um melhor aproveitamento do conteúdo que será apresentado neste capítulo. Como visto nos capítulos anteriores, a ideia de classe na linguagem Java é o núcleo de todo o processo da orientação a objetos, no qual podemos representar qualquer objeto, seja ele concreto, tal como um carro, seja mesmo abstrato, tal como um softbot.

Mas, não podemos deixar de mencionar outros conceitos importantes que auxiliam a concretizar o paradigma, como, por exemplo, os atributos e os métodos, conhecidos no capítulo anterior, ou mesmo os métodos construto-res, destrutores e a ideia de encapsulamento na qual iremos trabalhar. Tais ferramentas tecnológicas possibilitam que a linguagem Java possa descrever com maior clareza o problema e com isso, obter uma solução melhor. O pri-meiro conceito no qual iremos trabalhar são os construtores e sua função no paradigma e na linguagem Java.

3.1 Construtores

Em nosso segundo capítulo, analisamos a criação de objetos, que de-nominamos de instanciação de um objeto. Ali, obtínhamos uma referência para um espaço de memória, lembra? Pois bem, como vimos, isso nos obriga a seguir uma determinada sintaxe, conforme é apresentado a seguir.

Carro novoCarro = new Carro();

Já foi analisada a utilização da palavra reservada new no ato da ins-

tanciação de um objeto ao verificar sua responsabilidade pela nova instância. Mas, podemos dizer que é uma meia verdade. Isto porque, como visto no exemplo anterior, o operador new antecede a chamada de um método. É esse

52 JAVA com Orientação a Objetos

método que denominamos de construtor do objeto ou apenas construtor. Sua função, como o próprio nome explicita, é construir, ou melhor,

preparar o espaço de memória definido para um objeto para receber os da-dos conforme determinado na estrutura definida na classe. Sua invocação geralmente é feita no momento da criação de um objeto, da mesma maneira como é feita para qualquer método. Porém, um detalhe a ser considerado é que os métodos construtores possuem o mesmo nome da classe na qual são definidos.

Por definição, os métodos construtores são métodos especiais invo-cados pelo sistema na instanciação de um objeto, sendo que o operador new apenas informa qual método construtor de uma determinada classe será uti-lizado pela JDK no momento da criação do objeto para inicializar os valores dos atributos.

Neste caso, cabe um exemplo para ter uma melhor visualização dos conceitos. No exemplo a seguir, definimos um método para a classe Car-ro. Transcreva o código e tente visualizar as peculiaridades dos métodos construtores.

// Classe Carro.java

package conceitos;

public class Carro {

// atributos

Boolean chave = true;

// métodos construtores

public Carro(){

this.chave = true;

}

public Carro(Boolean chave){

this.chave = chave;

}

// métodos funcionais

public void ligar() {

Capítulo 3 - Construtores, destrutores e encapsulamento 53

chave = true;

System.out.println(“Ligar”);

}

public void desligar() {

chave = false;

System.out.println(“Desligar”);

}

}

No exemplo apresentado, foi criada a classe Carro, sendo definidos dois métodos funcionais: ligar e desligar. Pois bem, mas o que realmente im-porta para nós está na definição dos métodos construtores. Repare que no exemplo, foi definido o método público Carro(). Ele consiste em um método construtor.

A invocação de um método construtor nada mais é que uma referência para a área de memória onde foi criado o novo objeto, podendo ser traba-lhados os valores de inicialização do objeto. Desta forma, podemos, então, dizer que o método construtor é responsável pela definição e pela alocação de memória para um novo objeto.

Como mencionado, um método construtor deve possuir o mes-mo nome da classe, porém verifique que, para tal método, não é definido nenhum tipo de retorno. Isso acontece sempre e com qualquer que seja o método construtor ou mesmo objeto a ser inicializado, pois nosso método construtor é responsável por estruturar o espaço de memória e inicializar os valores para os atributos de uma classe, não por fazer operações funcionais do objeto criado e retornar valores.

O método construtor apresentado sem parâmetros também é conhe-cido como método construtor DEFAULT, sendo o mais comum. Nele, podem ser realizadas todas as inicializações citadas para os métodos construtores parametrizados. Outro aspecto interessante a ser destacado sobre os méto-dos construtores é a capacidade fornecida pela própria JVM, que no caso de não ser definido nenhum método construtor para uma classe, a própria JVM fica responsável por disponibilizar um método construtor para a inicializa-ção do espaço de memória no ato da instanciação de um objeto. Esse método, porém, sempre será vazio, sem parâmetros e sem inicializações com valores para seus atributos. Um exemplo para tal citação é a criação do objeto ‘chave’ demonstrado no quadro anterior, no qual é utilizado o construtor default.

54 JAVA com Orientação a Objetos

Em vários problemas, é interessante que os valores de determinados atributos sejam inicializados no momento da instanciação dos objetos, como ocorreu no nosso exemplo. No caso, podem ser criados quantos métodos construtores forem necessários, diferenciados apenas pela lista de parâme-tros definida para o método construtor PARAMETRIZADO. Assim, podem ser passados valores para a inicialização dos atributos da classe no momento de sua instanciação. Outra importante função dos métodos construtores é a possível realização operações que auxiliem e interfiram no funcionamento de um objeto, abrindo arquivos, estabelecendo comunicação, inicializando dispositivos que serão úteis ao programa.

Carro novoCarro = new Carro(Boolean chave);

Resumidamente, uma classe Java pode possuir diversos construto-res, todos obrigatoriamente devem possuir o mesmo nome da classe, SEN-DO SOMENTE UM DEFAULT, diferenciados por sua assinatura, no caso, suas listas de parâmetros. Isto é o que denominamos de sobrecarga do cons-trutor.

Isto torna o conceito de orientação a objetos mais próximo da reali-dade, facilitando o uso de classes em diferentes contextos e circunstâncias. Detalhe importante a ser mencionado aqui é o fato de um método construtor poder fazer a chamada de outros métodos da classe ou mesmo instanciar no-vos objetos, realizando assim, a chamada de métodos construtores de outras classes e com isso, possibilitando a construção de objetos que se completam e definem de maneira mais realista a representação do problema, já que, con-forme vimos, em sua maioria, um programa é composto por várias classes que se comunicam por meio de mensagens.

Uma vez criados os objetos, é interessante para nossa programação entender a liberação dos recursos de memória utilizados. Para isso, iremos detalhar e trabalhar com os destrutores e o coletor de lixo.

3.2 Destrutores e Garbage Collector (Coletor de Lixo)

Na tecnologia Java, existem os construtores que realizam as ope-rações iniciais de um objeto, preparando-o para o correto funcionamento, além da alocação de memória para estas, mas existem também os métodos

Capítulo 3 - Construtores, destrutores e encapsulamento 55

destrutores. Assim como os construtores, o destrutor é uma característica oriunda da linguagem C++. É um método especial que tem por finalidade liberar o espaço de memória utilizado por um objeto e com isso, finalizar qualquer operação que esteja em andamento, como, por exemplo, fechar ar-quivos, encerrar a comunicação e liberar os recursos alocados no sistema, e com isso, eliminar qualquer vestígio da instância do objeto. Os métodos destrutores seguem uma sintaxe padrão, conforme é apresentado a seguir.

!������"��������?�&'�

// Aqui é geralmente utilizado

// para liberar recursos.

}

Como apresentado, um método destrutor deve sempre ser identifi-cado pelo nome finalize() e pode ser invocado a qualquer momento. Outro detalhe que pode ser percebido quanto aos destrutores é que ao contrário dos construtores, que podem conter parâmetros em sua assinatura, os des-trutores não têm parâmetros na assinatura do método, porém sempre deve ser definido o valor de retorno como void.

A real finalidade dos destrutores é liberar do sistema a memória usa-da durante a execução do objeto, sendo que este é um dos mais complexos problemas encontrados no desenvolvimento de sistemas. Isto é devido ao fato de que os recursos de um sistema são finitos. Importante detalhe a ser citado é que a invocação de um método destrutor não caracteriza a finaliza-ção concreta do objeto instanciado, mas sim, apenas uma sinalização para que o sistema, assim como definido pela JVM, libere os recursos recolhendo o espaço de memória do objeto destruído. É aí que surge outro conceito.

3.2.1 Garbage Collector

Preocupados com o problema do estouro de memória comum e en-contrado em diversas linguagens, os criadores da tecnologia Java incorpora-ram à maquina virtual um mecanismo que tem como objetivo a liberação da memória automaticamente, que é executado simultaneamente ao programa Java. Este recurso é denominado Garbage Collector ou mais popularmen-te conhecido como Coletor de Lixo. No Java, conforme mencionado no

56 JAVA com Orientação a Objetos

capítulo anterior, um objeto sempre referencia um endereço de memória, porém quando esse endereço deixa de ser referenciado pelo programa, no caso, sai do processo de execução do programa em questão, este espaço de memória é marcado para uma futura liberação pelo Garbage Collector. A ideia é que uma vez marcado como um objeto no qual seu espaço de memória pode ser devolvido para o sistema, o coletor de lixo devolve a memória ao sistema para uma futura utilização.

Tal sinalização é feita por meio dos métodos destrutores já vistos. Outro aspecto interessante do coletor de lixo está no fato de que este me-canismo tenta sempre se antecipar aos possíveis erros, oriundos da falta de recursos do sistema. Para isso, quando não há mais memória disponível no sistema, o garbage collector faz uma varredura para obter os espaços de me-mória ociosos para sua liberação de imediato para o sistema, prevenindo er-ros de estouro de memória.

Considerando tais elementos da tecnologia Java, um aspecto positi-vo é que não é necessário o tratamento para a liberação da memória, ficando a critério do programador a utilização dos métodos destrutores, diferente-mente de outras linguagens de programação, como, por exemplo, o C++, que deve realizar tal tratamento. Um detalhe importante para finalizar nossa análise sobre o coletor de lixo e os métodos destrutores está no fato de que um objeto no Java pode ser eliminado com uma nova inicialização, por meio da invocação dos métodos construtores que irão reiniciar a referência de uma variável ou um atributo. No caso, o objeto perderá a referência ao espaço de memória anterior. Outra possibilidade de fazer com que o coletor de lixo libere recursos é atribuir o valor null a um objeto, sendo que com isso, sua re-ferência de memória ficará à disposição. Tais possibilidades são importantes, pois garantem que não ocorram erros no sistema, devido à falta de recursos do hardware.

3.3 Encapsulamento

Iremos, agora, trabalhar com outro importante elemento conceitual do paradigma de programação orientada a objetos - o encapsulamento. Este conceito é útil para garantir que a solução dos problemas propostos seja sem-pre realista e que cada elemento só enxergue o que realmente é importan-te. No caso, consiste em um mecanismo que é utilizado com a finalidade de esconder os detalhes de implementação das classes Java, de maneira a se

Capítulo 3 - Construtores, destrutores e encapsulamento 57

assemelhar à realidade dos objetos reais. O ponto central do conceito é pos-sibilitar uma maior segurança e domínio da complexidade, pois uma classe deve ofertar apenas o que ela pode fazer, não como ela faz.

Vamos ser um pouco mais claros. O objetivo do encapsulamento é que uma classe impeça que seus atributos e métodos sejam acessados diretamen-te. Para isso, o certo é disponibilizar apenas métodos públicos para o aces-so aos valores produzidos que realmente devem ser visualizados, ofertando apenas a real funcionalidade que a classe se propõe a realizar. Note que aqui é feita uma referência aos qualificadores de visibilidade apresentados em nos-so segundo capítulo, sendo: public, protected e private.

Tais características são oriundas da ideia cotidiana que encontramos e que geralmente passam despercebidas em nosso dia a dia na abstração de um objeto do mundo real. Vamos a um exemplo para ter um melhor entendimen-to. Ao assistirmos televisão ou mesmo ouvirmos um rádio, não temos ne-nhum conhecimento de como estes objetos trabalham internamente. Aqui, apenas são fornecidas interfaces ou maneiras de interagir com estes equi-pamentos, por exemplo: um botão para ligar/desligar ou mesmo aumentar/diminuir o volume. Todos esses elementos são funcionalidades que mexem com parâmetros ou propriedades internas (atributos) do equipamento. En-tão, o encapsulamento é útil na proteção dos atributos da classe, disponibili-zando, por meio de métodos, o acesso às propriedades da classe e com isso, a alteração do estado destas e do sistema.

Definindo os métodos de encapsulamento, eles fornecem uma forma de comunicação entre os usuários de uma classe e a implementação disponí-vel nesta, facilitando a escrita, manutenção e alteração dos programas. Exis-tem métodos convencionados entre os programadores Java que criam uma interface entre os atributos e o usuário, sendo uma camada de comunicação publica. São denominados métodos get e set vinculados a cada atributo das classes e evitam o acesso direto a tais atributos, aumentando a segurança ao impedir que a implementação e a forma como os atributos são tratados este-jam visíveis. Um exemplo desses métodos é apresentado no quadro a seguir.

// Classe Carro.java

package conceitos;

public class Carro {

// atributos

58 JAVA com Orientação a Objetos

private Boolean chave = true;

// método construtor

public Carro(){

setChave(true);

}

public Carro(Boolean chave){

setChave(chave);

}

// métodos de encapsulamento

private void setChave(Boolean status){

this.chave = status;

}

private Boolean getChave(){

return this.chave;

}

// métodos de funcionamento

public void ligar() {

setChave(true);

System.out.println(“###LIGADO###”);

}

public void desligar() {

setChave(false);

System.out.println(“###DESLIGADO###”);

}

// método destrutor

!������"��������?�&'�

chave = null;

}

}

Destrinchando o código apresentado no quadro anterior, observe que os métodos que descrevem o funcionamento da classe, aqui ligar e desligar,

Capítulo 3 - Construtores, destrutores e encapsulamento 59

não fazem mais referência direta aos atributos, como ocorria nos outros exemplos apresentados até aqui. Algumas partes do código devem ser cita-das. Note que o atributo-chave passou a ser declarado como privado, evitan-do o acesso de qualquer outra classe diretamente a ele. Foram implementa-dos os métodos set e get, que garantem o encapsulamento dos atributos, no caso, as interfaces de acesso para a inserção de valores e recuperação. Assim, garantimos que qualquer requisição desse atributo deve ser realizada através dos métodos get e set definidos para o atributo.

Nesta nova contextualização, os atributos devem obrigatoriamente ser acessados por meio de métodos. Os métodos set são utilizados para atribuir valores e os métodos get para a recuperação dos valores atuais dos atributos. Isso consiste em uma boa prática de programação que deve ser inserida em seu cotidiano, ainda mais no que tange à programação Java.

Vamos a mais um exemplo para demonstrar os vários conceitos vistos até aqui. Transcreva o programa a seguir e execute-o, conforme já foi realiza-do em vários exemplos dos Capítulos 1 e 2.

// Classe Carro.java

package conceitos;

import java.util.Scanner;

public class Carro{

// atributos

private Boolean chave = true;

// métodos construtores

public Carro(){

setChave(true);

}

public Carro(Boolean chave){

setChave(chave);

}

// métodos de encapsulamento

private void setChave(Boolean status){

this.chave = status;

}

60 JAVA com Orientação a Objetos

private Boolean getChave(){

return this.chave;

}

// métodos de funcionamento

public void ligar() {

setChave(true);

System.out.println(“###LIGADO###”);

}

public void desligar() {

setChave(false);

System.out.println(“###DESLIGADO###”);

}

// método destrutor

!������"��������?�&'�

chave = null;

}

// método executável

public static void main(String[] args){

Scanner scn = new Scanner(System.in);

Carro novoCarro = new Carro();

System.out.println(“Digite 1 para ligar \n 2 para“

+ desligar);

int opcao = scn.nextInt();

switch(opcao){

case 1: novoCarro.ligar();

break;

case 2: novoCarro.desligar();

break;

}

}

}

Capítulo 3 - Construtores, destrutores e encapsulamento 61

No exemplo, é solicitada uma entrada ao usuário que define qual será a funcionalidade a ser acessada. Para tanto, a classe Scanner é responsável por capturar essas entradas em um console, sendo utilizado o método nextInt( ). O programa apresentado inicialmente importa a classe Scanner para que pos-samos capturar uma entrada do teclado, criando uma interação com o usuá-rio. Após a definição da classe Carro, foi criado o atributo-chave, bem como os métodos de encapsulamento get e set para acesso a este. Foram criados os métodos construtores, configurando a sobrecarga dos construtores, com um possuindo parâmetros e o outro, não.

Um importante detalhe a ser mencionado para os construtores é que, caso o programador defina pelo menos um método construtor, o método default disponibilizado pela própria JVM deixará de existir, sendo necessária a declaração do método construtor default pelo programador, conforme é exemplificado. Este é um conceito que está relacionado à ideia de polimor-fismo que iremos explorar mais a fundo no próximo capítulo. Por enquan-to, atente ao fato de que sempre que um método construtor for definido, o método default disponibilizado pela JVM deixará de existir e você deverá fornecê-lo, caso queira utilizá-lo. Finalizando, o exemplo anterior possui um método executável que define uma instância, no caso, o objeto da classe car-ro denominado ‘novoCarro’ que permite o acesso ao espaço de memória com seus atributos e métodos.

Assim, finalizamos mais um capítulo, no qual conhecemos os elemen-tos do paradigma da programação orientada a objetos. Fica como sugestão que todos os exemplos sejam refeitos para que todos os conceitos vistos se-jam mais bem assimilados. Em nosso próximo capítulo, continuaremos a tra-balhar com a orientação a objetos aplicada à tecnologia Java.

Capítulo 4 Herança, polimorfismo e interface

Caro leitor, neste capítulo iremos conhecer outros conceitos ainda vinculados ao paradigma da programação orientada a objetos. Sendo bem mais específico, poderíamos dizer que este é o mais importante dos capítulos estudados até aqui, pois daremos os princípios que tornam o paradigma e a tecnologia diferenciados.

Como mencionado diversas vezes no decorrer do livro, o paradigma da Programação Orientada a Objetos (POO) trabalha determinando um retrato fidedigno dos objetos do mundo real. Logo, nada mais sensato e interessante que a existência de um conceito que denote a hierarquia existente entre os objetos reais. Tal conceito é de extrema importância e diferencia a linguagem de programação Java que, aliada à orientação a objetos, possibilita um me-lhor aproveitamento e reutilização do código por meio da ideia de herança.

Outra característica da POO que iremos analisar está vinculada ao po-limorfismo. A palavra polimorfismo é oriunda da palavra grega polimorfos, que significa diversas formas. Este conceito é fundamental, já que possibilita chamadas ou invocações semelhantes para diferentes implementações por meio da redefinição ou da sobrecarga de métodos.

Finalizando, neste capítulo ainda conheceremos o conceito de interface, que nos possibilitará uma maior abstração da modelagem do mun-do real para as classes no Java. Isso torna a linguagem Java mais extensível e reutilizável.

4.1 Herança

Como mencionamos, iremos trabalhar nesta seção com um dos mais importantes conceitos da orientação a objetos, se não o mais importante: a herança. Este, por sua vez, consiste na aplicação de uma técnica muito simples e que segue os preceitos do mundo real. Um bom começo para o en-tendimento da herança é vislumbrar os aspectos já bem conhecidos da estru-tura familiar, na qual existe uma hierarquização entre pais e filhos, normal a qualquer ser humano. Ao definir a herança, pode-se dizer que consiste em

64 JAVA com Orientação a Objetos

uma técnica na qual uma determinada classe, denominada subclasse, utiliza atributos e métodos já definidos em outra classe denominada superclasse (pai), especificada como ancestral da subclasse (filho).

Sendo mais claro, a herança consiste no compartilhamento de atri-butos e métodos, assim como acontece num relacionamento genético do tipo pai e filho. A classe-pai, que é denominada superclasse ou classe base, possui definições gerais que podem ser utilizadas nas classes-filho, também conhe-cidas como subclasses. Isto significa que podem ser definidas classes mais genéricas, ou seja, em um sentido mais amplo, sendo refinadas sucessiva-mente em subclasses que herdam todas as características das classes mais genéricas, sendo assim mais específicas.

Isso é conhecido como especificação de uma classe. A especificação, termo muito utilizado quando se fala de herança, centra no fato de que as subclasses possuem características próprias que as diferenciam das classes--pai ou mesmo de outras classes que também herdam das mesmas super-classes, das quais são herdados atributos e métodos. Um exemplo disso seria imaginarmos uma estrutura familiar, no qual um filho herda de seu pai diver-sas características, tais como a cor dos olhos, cabelos e voz. Porém, esse filho, que herda tais atributos, possui características que são especificamente suas, como, por exemplo, o jeito de andar ou mesmo de correr. Isso o torna mais especifico que o ente do qual herdou várias características, no caso, seu pai. Podemos considerar que sempre que uma classe herda de outra, a classe que herda passa a ser um tipo especial da classe-pai.

Complicado? Veremos que não. Vamos a mais um exemplo, desta vez contextualizado a linguagem Java para clarear esta ideia. Tome como exem-plo uma subclasse Paciente que herda todos os atributos e métodos de uma superclasse Pessoa, sendo assim, um paciente é um tipo de pessoa, porém mais especifico, já que além de herdar todos os atributos e métodos definidos na classe-pai, no caso a classe Pessoa, a Paciente tem seus próprios atributos e métodos que a diferenciam para o contexto que se predispõe a representar.

Caro leitor, acredito que devidamente apresentado o conceito de he-rança, é necessário conhecermos a sintaxe para sua utilização na linguagem Java. O conceito de herança, no qual uma classe estende outra, é realizado por meio da utilização da palavra reservada extends, conforme é demons-trado hierarquicamente no quadro a seguir.

Capítulo 4 - Herança, polimorfismo e interface 65

// Classe SuperClasse.java

public class SuperClasse{

//atributos e métodos da superclasse

}

// Classe SubClasse.java

public class SubClasse extends SuperClasse{ //atributos e métodos da subclasse

}

No quadro anterior, é interessante notar que a superclasse não recebe nenhuma marcação que a diferencia. Porém, repare que para a subclasse, é definida a herança por meio da palavra reserva extends, que a torna uma extensão da superclasse. Com isso, podemos dizer que a subclasse, mais es-pecífica, possui o comportamento da superclasse.

Outro ponto importante a mencionar, que é oriundo da utilização dos procedimentos de herança, é a utilização da palavra reservada super. Sua função é possibilitar à subclasse o acesso à superclasse. Assim, quando for necessário acessar algum método ou atributo na superclasse, a sintaxe para tanto será “super.nomeMétodo( )”. Desta forma, você está explicitando que deseja invocar um método da superclasse. Outro detalhe importante é quanto a invocar o método construtor da classe base e isto pode ser feito através da invocação do método “super( )”.

Provavelmente, você ainda não deve ter percebido a importância do que foi dito até aqui. Pois bem, a importância está no fato de que, com a utilização dos princípios da herança, não é necessário que seja reescrita boa parte do código em um programa Java, pois tudo que já foi produzido na classe-pai fica à disposição da classe-filho. Outro detalhe importante a ser citado é que uma parte do código, que será comum a várias outras partes de um programa, pode ser escrita somente uma vez em uma classe-pai, como mencionamos. Com isso, caso seja necessária a manutenção de alguma parte desse código, não será necessário que seja alterado em todas as classes-filho, somente na classe-pai, e as demais subclasses herdarão a alteração. Do ponto de vista da manutenção do código, isso é um diferencial a ser considerado no processo de desenvolvimento com a tecnologia Java. Como nos demais con-ceitos trabalhados até aqui, vamos a um exemplo para fixar esse importante princípio da orientação a objetos que imita a realidade. Então, transcreva a classe a seguir.

66 JAVA com Orientação a Objetos

// Classe Pessoa.java

package consultorio;

public class Pessoa{

// atributos

String nome;

String endereco;

// métodos

public void setNome(String newNome){

this.nome = newNome;

}

public void setEndereco(String newEndereco){

this.endereco = newEndereco;

}

public String getNome(){

return this.nome;

}

public String getEndereco(){

return this.endereco;

}

public void andar(){

System.out.println("Estou andando");

}

}

Em nosso exemplo, foi definida a classe Pessoa, na qual estão detalha-das algumas características e comportamentos inerentes a uma pessoa real. Feito isto, contextualizando o problema, todos sabemos que um médico nada mais é que genericamente uma pessoa. Mas, não podemos deixar de consi-derar que ele, além de suas peculiaridades humanas, possui especificidades quanto ao exercício da profissão de um médico, que o diferem das demais pessoas, sendo assim, temos uma especificação da classe Pessoa.

Desta maneira, podemos dizer que um médico tem uma relação “é um(a)” pessoa, com características e métodos específicos a este e que devem

Capítulo 4 - Herança, polimorfismo e interface 67

ser considerados. Ao trabalhar com as relações do tipo “é um(a)”, temos uma chave para identificar e determinar quando uma classe deve ou não ser des-cendente de outra existente. Para ter uma melhor visualização do processo, transcreva a classe Medico e note que ela explicita o conceito de herança de atributos e métodos da classe Pessoa por meio da palavra reservada extends após o nome da classe.

// Classe Medico.java

package consultorio;

public class Medico extends Pessoa{

// atributos

String horario;

String especialidade;

// métodos

public void setHorario(String newHorario){

this.horario = newHorario;

}

public void setEspecialidade(String newEspecialidade){

this.especialidade = newEspecialidade;

}

public String getHorario(){

return this.horario;

}

public String getEspecialidade(){

return this.especialidade;

}

}

Como dito, note que os atributos e os métodos que definem um médi-co como pessoa não foram novamente reescritos, pois já foram definidos na classe Pessoa, sendo reaproveitados pela classe Medico por meio da herança. Com isso, aquilo que foi definido para certa classe não precisa ser repetido para uma classe mais especializada originada da primeira, logo, seus atribu-tos e métodos. Desta forma, o paradigma da orientação a objetos auxilia a

68 JAVA com Orientação a Objetos

reduzir a repetição do código em um programa e em sua manutenção. Para ter uma melhor visualização prática das vantagens obtidas com a

herança, vamos a um exemplo. Nele, utilizamos as classes criadas anterior-mente na definição de um programa executável, no qual é feito o cadastro de um médico. Note que aqui, começamos a fazer com que a solução de nossos problemas passe a ter uma característica modular, aumentando o reuso e fa-cilitando posteriormente a manutenção.

// Classe Consultorio.java

package consultorio;

import java.util.Scanner;

public class Consultorio{

public static void main(String[] args){

// instância da classe Medico

Medico novoMedico = new Medico();

Scanner scn = new Scanner(System.in);

// entrada de dados

System.out.println("#####Cadastro Clinico#####");

System.out.println("Entre com o nome do médico:");

novoMedico.setNome(scn.next());

System.out.println("Entre com o endereço do” +

“médico:");

novoMedico.setEndereco(scn.next());

System.out.println("Entre com o horario do” +

“médico:");

novoMedico.setHorario(scn.next());

System.out.println("Entre com a especialidade do” +

”médico:");

novoMedico.setEspecialidade(scn.next());

//impressão dos dados obtidos e mantidos para o

//objeto

System.out.println("\n####DADOS DO MÉDICO####");

System.out.println("Nome do médico:"+novoMedico.

getNome());

System.out.println("Endereço do médico:"+novoMedico.

Capítulo 4 - Herança, polimorfismo e interface 69

getEndereco());

System.out.println("Horário do médico:"+novoMedico.

getHorario());

System.out.println("Especialidade:"+novoMedico.

getEspecialidade());

}

}

No exemplo anterior, o mais importante a ser mencionado é que, mes-mo não definidos na classe Medico, os atributos e os métodos referentes ao nome e ao endereço, que são oriundos da classe Pessoa, estão disponíveis para a instância da classe Medico denominada novoMedico. Isto, relembran-do, só é possível graças à herança existente na classe Medico da classe Pes-soa, evitando a reescrita do código já existente na superclasse Pessoa para a subclasse Medico.

A utilização do processo de herança também é muito importante para as estruturas correlatas ou mesmo as definições de melhores práticas, como no caso de vários padrões do projeto. Fica como sugestão a leitura so-bre design pattern, que pode enriquecer seus programas, além de evitar, em muitos casos, o retrabalho.

Finalizando nossa seção que trata dos princípios da herança na orien-tação a objetos com Java, é importante citar que a linguagem não suporta a herança múltipla, assim como o C++. Entretanto, existem alternativas para lidar com tal limitação, que serão consideradas ainda neste capítulo.

Com isso, chegamos ao final desta seção, na qual trabalhamos a im-portante característica do paradigma de orientação a objetos, que é a heran-ça. Mas, iremos analisar outra característica não menos importante para a orientação a objetos baseada na tecnologia Java, o polimorfismo, que consis-te em uma estrutura fortemente dependente do processo de herança.

4.2 Polimorfismo

Como já dito na introdução deste capítulo, a palavra polimorfismo ad-vém do grego polimorfos e significa diversas formas. Como observado em sua essência epistemológica da palavra, o conceito segue os mesmo princípios. Sendo mais especifico, o polimorfismo nada mais é que a definição de mé-todos com o mesmo nome, que definem a solução de um mesmo problema,

70 JAVA com Orientação a Objetos

seja na própria classe, seja na superclasse. O conceito, mais um do paradig-ma da orientação a objetos, pode ser aplicado de duas formas: sobrecarga ou redefinição.

Com certeza, a forma mais simples de obter o polimorfismo é por meio da sobrecarga de métodos ou também conhecido como overload.

4.2.1 Sobrecarga

A sobrecarga, em sua essência, consiste na possibilidade de ter em uma mesma classe, vários métodos com o mesmo nome, “porém com assinatu-ras diferentes”. Mas, como assim com assinatura diferente? Certo, se você se lembra do conceito de assinatura visto em nosso primeiro capítulo, ele é aplicado aos métodos definindo o nome, tipo de retorno e lista de parâme-tros ou argumentos. Neste caso, o que foi citado é que apesar do nome ser igual, o tipo de retorno ou mesmo a lista de parâmetros deve ser diferente para um método.

Com isso, os métodos podem possuir o mesmo nome, sendo conside-rados diferentes por receberem um diferente número ou tipo de parâmetros, ou mesmo o tipo de retorno pode ser diferente. Este é um conceito muito simples de ser assimilado e para tanto, vamos utilizar nosso exemplo recor-rente da classe Carro, na qual pode acontecer o polimorfismo.

// Classe Carro.java

package fabrica;

public class Carro{

// atributos

Combustivel combustivel = new Combustivel();

// métodos

public void setCombustivel(Combustivel

newCombustivel){

this.combustivel = newCombustivel;

}

public Combustivel getCombustivel(){

return this.combustivel;

}

Capítulo 4 - Herança, polimorfismo e interface 71

KKU�����������������X�����������������

public void abastecer(Alcool abstAlcool) {

setCombustivel((Combustivel) abstAlcool);

System.out.println(“Abastecido com álcool”);

}

public void abastecer(Gasolina abstGasolina) {

setCombustivel((Combustivel) abstGasolina);

System.out.println(“Abastecido com gasolina”);

}

public void abastecer(BioDiesel abstBioDiesel) {

setCombustivel((Combustivel) abstBioDiesel);

System.out.println(“Abastecido com biodiesel”);

}

}

Aqui, é demonstrado um exemplo de sobrecarga dos métodos de uma mesma classe, no qual um carro pode ser abastecido de diversas maneiras, porém a essência da função é a mesma, no caso, abastecer o carro para que ele possa andar. É importante mencionar que o exemplo apresentado é apenas ilustrativo, uma vez que não foram apresentadas as classes Combustivel e suas especificações, no caso, Gasolina, Alcool e BioDiesel, que também foram utilizadas no exemplo. A ideia aqui é que seja entendida a essência do concei-to de polimorfismo e sua abstração do mundo real.

Conforme pode ser observado, em nosso dia a dia, uma mesma fun-cionalidade pode ser desempenhada de várias maneiras, porém devendo ser guardadas as devidas especificidades de funcionamento de cada uma. O exemplo disso é um carro bicombustível. Em nosso exemplo, mais um ele-mento importantíssimo que foi utilizado deve ser comentado - o cast.

4.2.2 CastO cast é a forma mais comum de conversão de tipos, porém sua utili-

zação possui algumas peculiaridades que devem ser observadas na hora da

72 JAVA com Orientação a Objetos

utilização do recurso. O cast no Java pode ser realizado de duas formas, con-siderando a conversão dos tipos, sendo: implícito e explícito. Estes recursos, por sua vez, estão geralmente associados à utilização do conceito de herança, no qual, como vimos, uma classe-filho (subclasse) é semelhante à classe-pai (superclasse), da qual foram herdados os atributos e os métodos.

É deste ponto que podemos partir para o entendimento do cast im-plícito. Neste caso, toda subclasse pode ser associada à declaração de uma superclasse. Esta é a forma mais simples, pois não há a necessidade de utili-zação de nenhum recurso adicional para ser efetuado, sendo apenas descrito por meio da declaração convencional de um objeto da classe-pai e do método construtor da classe-filho. Para ter uma melhor visualização, vamos a um exemplo.

Pai objeto = new Filho();

Em nosso exemplo, o objeto é declarado como uma instância da classe--pai, porém ele é ‘construído’ como sendo do tipo da classe filho, ou seja, re-cebe uma área de memória referente à subclasse. Note que há uma conversão natural, pois ambos são semelhantes devido ao processo de herança. Gros-seiramente, poderíamos dizer que isso é possível, pois a classe-filho pode ser hierarquicamente inferior à classe-pai, conhece e sabe que ela própria é do tipo superclasse e, portanto, não precisa necessariamente ser informada que será convertida. Isto é feito no momento em que utilizamos a palavra extends na classe-filho, ou seja, a herança.

Já o cast em sua forma explicita, é denominado assim, pois é necessá-ria a informação para a Máquina Virtual Java de qual classe se deseja fazer a conversão, no caso o cast. Neste caso, de uma classe-pai, tenta-se convertê--la em uma classe-filho. Porém, ao fazer novamente uma análise hierárquica para ter um melhor entendimento, a superclasse não sabe e em momento algum é informada quais são suas classes-filho. Portanto, é necessário infor-mar explicitamente em qual tipo de classe-filho a instância da classe-pai será convertida. Então, caro leitor, aqui o convido a verificar como isso pode ser realizado na linguagem Java, observando a sintaxe no exemplo a seguir.

Pai objetoPai = new Filho();

Filho objetoFilho = (Filho)objetoPai;

Capítulo 4 - Herança, polimorfismo e interface 73

Em nosso exemplo, o objeto declarado como objetoPai é instanciado como sendo do tipo da classe Filho. Logo após, a referência do objetoPai é convertida por meio de um cast explicito no objetoFilho. Estes conceitos são importantes para que possamos também conhecer outro importante ele-mento da linguagem Java - o operador instanceof.

4.2.3 instanceof

O instanceof é um operador utilizado para a realização de casts do tipo explícito, nos quais não se tem conhecimento de qual classe o define. Aqui, podemos trabalhar um pouco mais o exemplo apresentado da classe Carro quanto ao seu abastecimento. Vamos a ele então.

...

public void encherTanque(Combustível c){

if(c instanceof Alcool){

abastecer((Alcool) c);

}else{

abastecer((Gasolina) c);

}

}

...

No código anterior, repare que temos um método ‘encherTanque’ que recebe como parâmetro um objeto da classe Combustível. Dentro desse mé-todo, é verificado, por meio da utilização dos operadores condicionais if/else, qual o tipo de combustível. Para isso, dentro do teste, é utilizado o operador instanceof, que realiza a verificação de qual é o combustível selecionado. De acordo com o valor da instância, é chamado o método abastecer usando a sobrecarga de métodos.

Simploriamente, instanceof significa “instância de” ou “é do tipo”. As-sim, em nossa verificação anterior, no teste condicional o que é feito nada mais é que uma comparação para definir se o objeto passado como parâmetro é uma instância da classe Alcool ou da classe Gasolina.

74 JAVA com Orientação a Objetos

4.2.4 Sobrecarga de construtores

Outro exemplo que pode ser citado para o polimorfismo é a sobrecarga dos métodos construtores, onde são definidos diversos métodos com o mes-mo nome, porém com assinaturas diferentes. Tais considerações já foram feitas em nosso terceiro capítulo, no qual definimos dois métodos constru-tores para uma classe, pois, conforme visto, uma vez declarado um constru-tor, qualquer que seja sua assinatura, passa a ser obrigatória a definição do método construtor default para sua utilização, já que o método construtor fornecido pela JVM deixará de ser fornecido.

4.2.5 Redefinição

Nossa segunda forma de utilização do conceito de polimorfismo con-siste na redefinição de métodos ou também conhecido como sobrescrita (override), isso realizado sobre os métodos existentes nas superclasses. Tal conceito está baseado na herança, da qual as subclasses herdam atributos e métodos de uma classe-pai. Isso devido ao seguinte fato: Imagine que nem sempre os métodos fornecidos pela classe-pai são suficientes para resolver os problemas da subclasse, visto que a classe-filho é uma especialização, tendo suas particularidades a serem consideradas no processo. É aí que entra a so-brescrita dos métodos, na qual a subclasse reescreve um método utilizando a mesma assinatura definida na classe-pai, sendo que no momento da invoca-ção do método, dentro da subclasse, será acionado o método ali definido que se sobrepõe ao da superclasse. Vamos a um exemplo: imagine um pai e um filho, ambos são pessoas e assim, possuem características e comportamentos de um ser humano. É natural que o filho herde os trejeitos de seu pai, porém existem características e comportamentos que, por mais inerentes ao proces-so de herança que sejam, precisam ser especializados, ou seja, por mais que exista o processo de herança, ao falar, por exemplo, o filho possui especifici-dades em sua voz que são só suas, apesar da aproximada semelhança com a de seu pai.

Para o paradigma da orientação a objetos, uma operação, ação ou mes-mo uma transformação que um objeto realiza por meio dos métodos são im-plementações específicas das operações desejadas para uma classe. Então, mesmo que esta venha a herdar os atributos e os métodos de outra classe, sempre terão prioridade as características e os comportamentos definidos

Capítulo 4 - Herança, polimorfismo e interface 75

para o escopo específico da classe. Para ter um melhor entendimento, vamos a uma implementação. Altere a classe Medico do exemplo apresentado na seção anterior, no qual essa classe herda os atributos e os métodos da classe Pessoa.

// Classe Medico.java

package consultorio;

public class Medico extends Pessoa{

// atributos

String horario;

String especialidade;

// métodos

public void setHorario(String newHorario){

this.horario = newHorario;

}

public void setEspecialidade(String newEspecialidade)

{

this.especialidade = newEspecialidade;

}

public String getHorario(){

return this.horario;

}

public String getEspecialidade(){

return this.especialidade;

}

KK�������YZ����X���

public void andar(){

System.out.println("Estou andando rápido");

}

}

Note que no exemplo apresentado, foi criado na classe Medico o mé-todo andar( ). Tal método já havia sido definido na classe Pessoa, na seção anterior, e devido ao processo de herança existente entre as classes Pessoa e

76 JAVA com Orientação a Objetos

Medico, não foi necessária sua reescrita na classe filho, ou seja, na classe Me-dico. Porém, devido às características específicas da classe Medico, esse mé-todo é redefinido e, então, passa a atender as particularidades dessa classe. Assim, a máquina virtual Java entenderá que ao ser invocado um método, no qual houve o processo de redefinição, o método da subclasse será o que deve ser acionado. Caro leitor, acredito que até aqui você deve ter verificado que o conceito de polimorfismo é importantíssimo para o paradigma de orientação a objetos, assim como os demais mecanismos de abstração de dados, herança e encapsulamento já apresentados.

4.3 Interface

Amigo leitor, agora que já conhecemos os conceitos de herança e poli-morfismo, vamos a outro conceito-chave no paradigma da orientação a ob-jetos - as interfaces. O conceito de interface é um tanto amplo, já que ao trabalharmos com o Java, ele está constantemente presente. De um lado, como vimos, toda classe no Java tem um propósito específico, geralmente se relaciona com outras classes e aí, temos um sistema completo e funcional que se comunica por meio de mensagens. Essas mensagens são trabalhadas por meio dos métodos definidos segundo os modificadores de acesso e tais mé-todos são interfaces (entradas) para o acesso ao conteúdo de uma instância.

Mas, a tecnologia Java ampliou o conceito, tornando-o ainda mais flexível. Poderíamos dizer grosseiramente que a tecnologia Java possui um tipo especial de classe que são as interfaces. Isso ocorre devido à sintaxe de definição de uma interface no Java ser semelhante à utilizada para uma clas-se. Entretanto, no lugar do identificador class, deve ser utilizada a palavra reservada interface.

A ideia central do conceito de interface é a modelagem dos comporta-mentos que são esperados na definição de uma determinada classe. O nome interface coerentemente tem o objetivo de explicitar que esse conceito Java pretende disponibilizar um meio padronizado de acesso a diferentes tipos de implementação como uma interface propriamente dita.

Para isso, em uma interface são definidos apenas métodos abstratos e variáveis finais. Um ponto importante a ser destacado é o fato de uma interface não ter uma implementação para seus métodos ou mesmo ins-tâncias para suas variáveis. Logo, a utilização das interfaces garante que você sempre se concentre nos objetos e nos relacionamentos que existirão,

Capítulo 4 - Herança, polimorfismo e interface 77

construindo, desta forma, uma espécie de planta baixa do sistema para pos-sibilitar a construção baseada nos modelos existentes, definindo assim uma camada extra de abstração para seu sistema que servirá de base para o res-tante. O código a seguir apresenta a sintaxe para a definição de interfaces nos Java.

// Interface Aluno.java

package escola;

public interface Aluno{

!�#��������������^`�|~�~U���~����

!�#����#������������&'

public abstract int faltas();

!�#����#�����������&������'

!�#����#�����������&������'

}

Algumas considerações devem ser feitas e estar sempre em mente quanto à utilização das interfaces. Uma interface não pode ser instancia-da, sendo que seu objetivo é definir um modelo de comportamento abstra-to para as classes. Tais classes que se propõem a implementar a interface devem fornecer a implementação dos métodos declarados na interface ou, ao menos, declará-los em seu escopo. Uma boa analogia para as interfaces é imaginá-las como sendo um contrato, no qual qualquer classe que se propõe a implementar a interface deve, ao menos, declarar métodos e variáveis está-ticas e finais em seu escopo.

Note que no exemplo anterior, é feita a utilização da palavra reserva-da abstract. Ela pode referenciar tanto métodos quanto classes ao apresen-tar apenas a ideia ou mesmo um modelo do todo, sem que seja fornecida a implementação para tais métodos ou classe, deixando explícita somente a abstração do objeto. O conceito de abstração muitas vezes se confunde com o conceito de interface. A função das classes abstratas é forçar o programador a implementar subclasses para a resolução dos problemas. Assim, os métodos da classe abstrata são declarados com o modificador abstract e sem corpo.

Voltando ao conceito de interface, para que uma classe imple-mente uma interface, em sua definição deve ser colocado o identificador

78 JAVA com Orientação a Objetos

implements seguido da lista de interfaces separadas por vírgulas. Vamos a um exemplo de uma classe que implementa a interface aluno definida no quadro anterior.

// Classe AlunoImp.java

package escola;

public class AlunoImp implements Aluno{ // atributos

!��"��������������

private int faltas;

// métodos

!�#�����������&'�

return nota1(nota1)+nota2(nota2)/2;

}

public int faltas(){

return faltas;

}

!�#����������&������'�

this.nota1 = nota;

return nota1;

}

!�#����������&������'�

this.nota2 = nota;

return nota2;

}

}

Caro leitor, vamos entender o exemplo apresentado no quadro an-terior. Conforme pode ser observado, a classe AlunoImp implementa a interface Aluno e, então, deve fornecer uma implementação para os méto-dos declarados na interface Aluno, que foi construída anteriormente. Além de fornecer a ideia de um contrato entre as classes, conforme mencionado, outro aspecto que pode ser explorado no conceito de interface, consiste na ideia da plugabilidade. Vamos a um exemplo para deixar tal perspectiva

Capítulo 4 - Herança, polimorfismo e interface 79

mais clara. Imagine uma classe que utiliza uma determinada interface que disponibiliza os métodos abstratos para a conexão com um banco de dados. Assim, existem diversas formas de implementar uma conexão. Logo, po-demos ter uma interface que defina todas as maneiras como uma conexão pode ser implementada, cabendo ao desenvolvedor plugar o método que lhe for mais conveniente, isso sem a necessidade de alterações drásticas no pro-grama, uma vez que todas as classes que implementam tal interface para a conexão, de alguma maneira, deverá comprometer-se a fornecer todos os métodos, como em um contrato, independentemente da forma como será implementado cada método.

Vamos a outro exemplo clássico e bem simples para o entendimento da ideia de plugabilidade, que é elemento central em vários padrões de projetos utilizados. Pois bem, imagine uma empresa de software que possui um pro-grama de controle médico. Este pode ser aplicado tanto a clínicas para tratar pessoas quanto a clínicas veterinárias. Tal sistema é relativamente simples e realiza apenas o controle de pacientes. Verificando o funcionamento de am-bas as clínicas, os processos são idênticos, apesar de lidar com pacientes com-pletamente diferentes. Resumindo, o sistema pode ser utilizado em ambos os casos. Mas, como? No caso, poderia ser criada uma interface Paciente que definiria os métodos comuns aos pacientes, restando as classes que imple-mentam tal interface. Então, observe o código a seguir.

// Interface Paciente.java

package clinica;

public interface Paciente {

public void setNome(String nome);

public void setHistorico(String historico);

public String getNome();

public String getHistorico();

}

Observe a seguir que nossas classes Pessoa e Animal, que implemen-tam a interface Paciente, a partir deste momento deveriam ter as seguintes definições obrigatoriamente.

80 JAVA com Orientação a Objetos

// Pessoa.java

package clinica;

public class Pessoa implements Paciente {

// atributos

private String nome;

private String historico;

// Métodos

public void setNome(String nome) {

this.nome = nome;

}

public void setHistorico(String historico) {

this.historico = historico;

}

public String getNome(){

return nome;

}

public String getHistorico(){

return historico;

}

}

Definida a classe Pessoa, para a classe Animal teríamos uma semelhan-ça, uma vez que ela deve também implementar a interface Paciente.

// Animal.java

package clinica;

public class Animal implements Paciente {

// atributos

private String nome;

private String historico;

// Métodos

public void setNome(String nome) {

this.nome = nome;

Capítulo 4 - Herança, polimorfismo e interface 81

}

public void setHistorico(String historico) {

this.historico = historico;

}

public String getNome(){

return nome;

}

public String getHistorico(){

return historico;

}

}

Isso permite uma padronização dos procedimentos ou mesmo que o código possa ser utilizado duas ou mais vezes, dando extensibilidade ao programa, bastando apenas que seja construída uma nova classe que se pro-ponha a implementar a interface e assim, que se possam utilizar todos os demais benefícios de seguir tais regras. Para tanto, teríamos como declaração dos objetos das classes, por exemplo.

// Clinica.java

package clinica;

public class Clinica {

public static void main(String[] args){

Paciente p = new Pessoa(); Paciente a = new Animal();

// Dados para a pessoa

p.setNome(“Alex Coelho”);

p.setHistorico(“Apresentou problemas na” +

“garganta.”);

// Dados para o animal

a.setNome(“Totó”);

a.setHistorico(“Problemas na pata.”);

// Imprimindo os relatórios

82 JAVA com Orientação a Objetos

Relatorios r = new Relatorios();

r.imprimirRelatorio(p);

r.imprimirRelatorio(a);

}

}

Note que em ambos os casos, o espaços de memória construídos são diferentes, um para a pessoa ou para o animal. Porém, quanto à sua defini-ção, são do mesmo tipo, no caso instâncias da interface Paciente. Repare.

Paciente p = new Pessoa();

Paciente a = new Animal();

Isso nos garante uma padronização nos processos, fazendo com que outras funcionalidades do sistema possam ser utilizadas de forma extensível a vários produtos. No nosso caso específico, a vantagem de utilizar a interface Paciente se caracterizaria na utilização dos procedimentos de geração de re-latório, por exemplo, como é apresentado no código a seguir e já referenciado no exemplo anterior.

// Relatorios.java

package clinica;

public class Relatorios {

public void imprimirRelatorio(Paciente p) {

System.out.println(“Relatório de Pacientes”);

System.out.println(“Nome:”+p.getNome());

System.out.println(“Histórico:”

+p.getHistorico());

System.out.println(“Histórico:”

+p.getCadastro());

}

}

Para finalizarmos nosso capitulo, vamos a outra funcionalidade que o conceito de interface possibilita, sendo a manipulação da herança múltipla no Java.

Capítulo 4 - Herança, polimorfismo e interface 83

4.3.1 Herança múltipla

Embora a linguagem Java não forneça um mecanismo explícito que possibilite a herança múltipla, ou seja, uma classe herdar de mais de uma classe, com a utilização de interfaces é possível obter algo próximo da essên-cia do conceito, com a implementação de diversas interfaces por uma classe.

Como uma classe pode implementar diversas interfaces e deve prover implementações para os métodos declarados nas interfaces, obtém-se uma pseudosobrescrita dos métodos e com isso, ela disponibiliza todos os méto-dos e atributos para as classes que a utilizam. Para ter um melhor entendi-mento, vamos a mais uma analogia. Um exemplo clássico é o do carro anfí-bio, que possui características e comportamentos tanto de um carro quanto de um barco. Então, nosso primeiro passo é criar as interfaces que definem os métodos.

// Carro.java

package estaleiro;

public interface Carro {

public void puxarFreioDeMao();

}

�����������%�����������������������������?���

na herança múltipla.

// Barco.java

package estaleiro;

public interface Barco {

public void navegar();

}

Feito isso, agora é necessário criar a nossa classe CarroAnfibio que irá implementar as interfaces propostas e com isso, passará a ser obrigada a reescrever os métodos propostos nas interfaces. Assim, vamos ao que interessa. Transcreva o código a seguir e analise sua utilização.

84 JAVA com Orientação a Objetos

KK�����~��#�����"�

package estaleiro;

!�#�������������~��#��implements Carro, Barco {

public void puxarFreioDeMao() {

System.out.println(“Puxou o freio de mão!”);

}

public void navegar() {

System.out.println(“Navegando!”);

}

}

Repare no exemplo que com isso, garantimos o comportamento ambí-guo do objeto real com a utilização das interfaces que mapearam o problema. Acredito que com isso, você tenha conseguido visualizar toda a vantagem de utilizar interfaces, que consiste na definição de um protocolo que seja co-mum entre as classes, além de criar uma especificação do que uma classe deverá oferecer e implementar em termos de métodos, o que resulta numa forma de abstração.

Então pessoal, chegamos ao final dos principais conceitos do paradig-ma de programação orientada a objetos, porém isso não significa o final de nossa jornada. Nos próximos capítulos, iremos conhecer ferramentas inte-ressantes que irão possibilitar a você, caro leitor, ter um melhor aprovei-tamento da linguagem Java e dos conceitos do paradigma de programação orientada a objetos. Assim como nos capítulos anteriores, aproveite para re-fazer todos os exemplos propostos.

Capítulo 5 Ferramentas úteis para o dia a dia

Neste capítulo, iremos considerar diversas ferramentas para um pro-gramador Java. Elencar quais seriam as prioridades de um programador em seu cotidiano não é algo tão simples assim, porém com certeza a manipula-ção de strings, trabalho com datas e horas, definição de operações matemá-ticas e manipulação de vetores especiais estão entre as funções que mais se destacam. Assim como mencionado no início de nosso livro, tudo no Java consiste em classes, exceto os tipos primitivos. Relembrando nossos tipos primitivos: int, float, boolean etc. Nossas classes derivam da classe Object, que tem as definições padrão para qualquer classe. Logo, todas as funciona-lidades e operações que são fornecidas pela biblioteca padrão da tecnologia Java são definidas em classes que operam por meio de seus métodos. Diante disso, iremos abordar como a linguagem Java possibilita o trabalho com es-tas importantes ferramentas para o dia a dia.

5.1 Manipulação de strings

Como já vimos desde o início de nossa leitura, a classe String trata-se de uma das mais utilizadas, ao considerarmos que no cotidiano computacio-nal, em sua maioria, as operações dependem deste tipo de dado em sua en-trada. Pois bem, diversas linguagens apresentam formas diferentes de lidar com as strings, seja no formato de um vetor de caracteres, seja mesmo for-necendo uma operação responsável por desempenhar a função de elemento agregador destes.

A tecnologia Java fornece a classe String para a realização de opera-ções e a manipulação de palavras e frases. Como você deve já ter percebido, diferentemente dos tipos primitivos, tais como int, float e assim por diante, sempre que instanciamos um objeto do tipo String, com ‘S’ maiúsculo em sua inicial, isso denota, segundo a convenção existente entre os desenvolve-dores Java e já conhecida por você, que se trata de uma classe. Por se tratar de uma classe, ela nos fornece uma gama de serviços que podem ser acio-nados por meio de seus métodos. São tais métodos que tornam as classes

86 JAVA com Orientação a Objetos

diferenciadas dos tipos primitivos, como já citado. A tecnologia Java fornece classes que também auxiliam na manipulação dos principais tipos, como, por exemplo, Int, Float, classe Boolean, entre outras. Repare que aqui temos o mesmo padrão: todas as iniciais são maiúsculas, logo, todas são classes que agregam valores aos tipos de dados por meio de métodos.

Mas iremos apenas nos concentrar aqui na manipulação de strings com as principais operações possíveis utilizando o Java. Desta forma, conhe-ceremos os principais métodos disponibilizados pela classe String, começan-do pela utilização de seus métodos construtores.

5.1.1 Construtores da classe String

Assim como em todas as classes Java, é necessária a existência de um método construtor responsável por garantir a instanciação dos objetos do tipo String. Pois bem, a classe String fornece dois métodos construtores para a instanciação de seus objetos, sendo um parametrizado e outro default. Ou-tra forma, no entanto, de realizar a criação de nosso objeto é por meio da pas-sagem de valor explícita, ao qual o objeto fará sua referência. Vamos observar como pode ser realizada a criação de nossos objetos da classe String.

String s = “Palavra”;

String s1 = new String();

String s2 = new String(“Palavra”);

Repare que tudo que foi apresentado no quadro anterior não é novida-de. Vários exemplos já apresentados a você, leitor, nos demais capítulos fize-ram menção a alguma das possibilidades de criação ou instanciação de obje-tos da classe String. É vital para seus programas que o objeto seja construído com algumas das possibilidades mostradas, garantindo que não ocorra erro de pontos nulos, sem uma referência de memória.

5.1.2 Outros métodos

Considerando inicializados nossos objetos, vários métodos são úteis para a manipulação de Strings, como segue na Tabela 5. Consideremos um objeto ‘s’ do tipo String para a sintaxe.

Capítulo 5 - Ferramentas úteis para o dia a dia 87

Tabela 5. Principais métodos da classe String.

Método Função Sintaxe

length( )Retorna o número de caracteres da

string.Int tamanho = s.lenght( );

charAt(int)Captura um caractere na posição

especificada na string.char caractere = s.charAt(3);

equals(String)Compara duas strings e retorna um

valor booleano (verdadeiro ou falso)Boolean iguais = s.equals(s1);

equalsIgnoreCase(String)

Compara duas strings ignorando a

diferença entre minúsculas e maiús-

culas e retornando valores booleanos.

Boolean iguais =

s.equalsIgnoreCase(s1);

compareTo(String)

Compara duas strings e retorna 0

se ambas forem iguais. Se a string

que chama o método for menor que

a passada como parâmetro, será re-

tornado um número negativo e caso

contrário, um número positivo.

Int result = s.compareTo(s1);

substring(int)

substring(int, int)

Retorna um novo objeto String a

partir do ponto especificado em

valor inteiro ou, então, delimitando a

posição inicial e final.

String nova = s.substring(3);

String nova =

s.substring(3,5);

indexOf(char)

Retorna a posição da primeira ocor-

rência do caractere passado como

parâmetro na string que invocou o

método.

Int posicao = s.indexOf(‘A’);

88 JAVA com Orientação a Objetos

toUpperCase( )Retorna um novo objeto String com

todos os valores em maiúsculo.

String nova = s.toUpperCase(

);

toLowerCase( )Retorna um novo objeto String com

todos os valores em minúsculo.

String nova =

s2.toLowerCase( );

Amigo leitor, como você deve ter percebido, a classe String fornece di-versas possibilidades que podem tornar a vida do programador mais fácil. Outros métodos da classe String poderiam ser considerados aqui. Assim, fica como dica que você verifique na documentação oficial da classe String as de-mais possibilidades para a manipulação das strings.

Porém, nem só de strings vive um programa, outras classes devem ser consideradas como elementos comuns e interessantes para o cotidiano de um desenvolvedor Java. Entre tais classes, podemos citar as classes que auxi-liam na manipulação de datas e horas, sendo nosso próximo assunto.

5.2 Data e hora

Um dos elementos que mais geram problemas e controvérsias na programação Java, com certeza consiste na manipulação de datas e horas. Isso pode tomar proporções ainda maiores quando falamos de aplicações que irão rodar e depender da Internet e de seus diversos servidores espalhados pelo mundo.

Considerando tais problemas, a tecnologia Java fornece um conjun-to de classes que, conforme já vimos, disponibilizam uma grande variedade de métodos que possibilitam o trabalho com datas e horas. As principais clas-ses que são utilizadas para a manipulação de datas são: java.util.Date, java.util.Calendar e java.util.GregorianCalendar. É importante mencionar que a classe Date está em desuso e, portanto, em processo de depreciação, o que pode fazer com que nas próximas versões da máquina virtual Java, ela não seja mais fornecida e os sistemas que a utilizam tenham problemas devido à sua falta. Mas, ainda assim, é importante apresentá-la ao considerarmos que diversos sistemas ainda a utilizam. Certo, então, nada melhor que apresentar sua utilização com um código. Logo, transcreva o código a seguir e execute-o.

Capítulo 5 - Ferramentas úteis para o dia a dia 89

// ExemploData.java

import java.text.SimpleDateFormat;

import java.util.Date;

import java.util.GregorianCalendar;

public class ExemploData {

public static void main(String[] args) {

Date d = GregorianCalendar.getInstance().

getTime();

SimpleDateFormat format = new SimpleDateFormat();

System.out.println(format.format(d));

}

}

Com a execução do programa, você deve ter percebido outra possibi-lidade da classe Date, que consiste na manipulação de informações sobre o tempo, tais como: hora, minutos, segundos e milissegundos. No exemplo apresentado, note que a data impressa segue o padrão americano e para isso, é necessária a manipulação de sua formatação, que é feita no método construtor da classe SimpleDateFormat. Essa classe fornece um conjunto de caracteres padrão para a formatação do objeto Date. Podemos citar alguns exemplos de formatações de datas, como a seguir.

dd/MM/yy = 21/08/11

dd/MMM/yyyy = 21/AGO/2011

Para obtermos a formatação no padrão brasileiro, criaremos uma classe alte-rada no trecho que se refere ao método construtor da classe SimpleDateFormat, como apresentado a seguir. Execute o código e verifique sua saída.

// Data.java

import java.text.SimpleDateFormat;

import java.util.Date;

import java.util.GregorianCalendar;

public class Data {

90 JAVA com Orientação a Objetos

public static void main(String[] args) {

Date d = GregorianCalendar.getInstance().getTime();

SimpleDateFormat format = new SimpleDateFormat(“dd/MM/yy”); System.out.println(format.format(d));

}

}

É importante mencionar aqui que a classe SimpleDateFormat conta com a utilização de diversos caracteres que auxiliam na formatação para a manipulação de datas e as mesmas, estão disponíveis em sua documentação padrão. Outra maneira de obtermos a data pode ser com a utilização das clas-ses DateFormat e Locale.

A classe Locale é importante, pois auxilia na designação do local e no processo de alteração dos padrões regionais. A mesma já vem com diversas regiões preconfiguradas como constantes, que apenas necessitam ser deter-minadas no momento de sua implementação. Já a classe DateFormat, define alguns padrões que podem ser aplicados a uma data ou hora. Vamos a um exemplo para sua fixação.

// DataFormatada.java

import java.text.DateFormat;

import java.util.Locale;

import java.util.Date;

public class DataFormatada {

public static void main(String args[]){

Date d = new Date();

Locale local = new Locale («pt»,»BR»);

DateFormat df = DateFormat.getDateInstance(

DateFormat.LONG, local);

System.out.println(“Hoje são: “+ df.format(d));

}

}

Porém, como mencionado, a classe Date está em processo de desconti-nuação e dessa forma, a tecnologia Java passa a fornecer outras classes para

Capítulo 5 - Ferramentas úteis para o dia a dia 91

a manipulação de datas. A principal, com certeza, consiste na Calendar. A classe Calendar consiste em uma classe abstrata, ou seja, contém as abstra-ções que definem uma data e hora, e desta forma, disponibiliza atributos e métodos para a manipulação de datas, uma vez que a data e a hora existem em qualquer lugar. Mas, o fato de ser uma classe abstrata não permite a ins-tanciação direta por meio do operador new. Assim, para instanciar um obje-to Calendar, caro leitor, você deve utilizar o método estático sobrecarregado getInstance( ), que na maioria das vezes é herdado da classe GregorianCalendar. A classe Calendar permite que várias operações sejam aplicadas a uma data, enriquecendo o que já é ofertado pela classe Date. Para entender sua mani-pulação, vamos a um exemplo.

// ExemploDataCalendar.java

import java.text.DateFormat;

import java.util.Calendar;

import java.util.Date;

public class ExemploDataCalendar {

public static void main(String args[]){

Date d = new Date();

Calendar calendario = Calendar.getInstance();

calendario.setTime(d);

DateFormat df = DateFormat.getDateInstance(

DateFormat.SHORT);

System.out.println( df.format(calendario.getTime()));

}

}

Repare que no exemplo, utilizamos uma instância da classe Date para

definirmos a data atual passada pelo sistema, porém poderíamos também ter, ao invés de utilizado o objeto do tipo Date, definido por meio de String os diversos parâmetros de uma data ou mesmo hora. Segue um exemplo para a visualização.

92 JAVA com Orientação a Objetos

...

calendario.set(ano,mês,dia);

calendario.set(ano,mês,dia,hora,minuto);

calendario.set(ano,mês,dia,hora,minuto,segundo);

...

Porém, nem sempre é interessante utilizar a classe Date, dada sua atu-al situação, sendo que a própria classe Calendar com a utilização do método getInstance( ) já fornece todo o suporte necessário para a aquisição da data. Além disso, o objeto do tipo Calendar, no nosso caso, calendário, pode ser utilizado para a manipulação dos elementos vinculados à data por meio de suas constantes, além de realizar, como já dito, operações como, por exem-plo, a soma ou a subtração dos dias em uma data. Como nos demais tópicos trabalhados até aqui, vamos a mais um exemplo.

// DataCalendario.java

import java.text.DateFormat;

import java.util.Calendar;

import java.util.Locale;

public class DataCalendario {

public static void main(String args[]){

Calendar calendario = Calendar.getInstance();

DateFormat df = DateFormat.getDateInstance(

DateFormat.SHORT, Locale.UK);

System.out.println(df.format

(calendario.getTime()));

System.out.println(Calendar.DAY_OF_MONTH);

System.out.println(Calendar.DAY_OF_WEEK);

System.out.println(Calendar.DAY_OF_YEAR);

calendario.add(Calendar.DAY_OF_YEAR,10);

//adiciona 10 dias à data atual

calendario.add(Calendar.MONTH,5);

//adiciona 5 meses à data atual

calendario.add(Calendar.YEAR,2);

//adiciona 2 anos à data atual

System.out.println(df.format

(calendario.getTime()));

Capítulo 5 - Ferramentas úteis para o dia a dia 93

}

}

No exemplo anterior, utilizamos duas classes conhecidas, DateFormat e Locale. Note que utilizamos a constante “Locale.UK” que define que segui-remos os aspectos regionais da Grã-Bretanha. Logo depois, é feita a impres-são da data e algumas operações para, então, termos uma nova impressão da data com os valores alterados. É claro que existem diversos outros métodos e constantes que a classe Calendar oferta e, logo, para serem obtidas maiores explicações, podem ser acessadas na documentação oficial.

5.3 Operações matemáticas

Outra classe importante para o cotidiano de um programador Java é a java.lang.Math. Ela disponibiliza diversos métodos e constantes para as operações matemáticas que podem ser acessadas de maneira estática, ou seja, não é necessário realizar a instanciação de um objeto. Exemplos das diversas possibilidades são as constantes π (pi) e ln (base dos logaritmos na-turais, também chamado de número de Euler ou logaritmo neperiano), sen-do respectivamente 3,141592653589793 e 2.718281828459045. Essas duas constantes podem ser acessadas conforme o exemplo a seguir explicita.

// Matematica.java

public class Matematica {

public static void main(String args[]){

// Cálculo do comprimento de um círculo

���������

double comp = 2 * raio * Math.PI;

System.out.println(comp);

// Logaritmo neperiano

System.out.println(Math.E);

}

}

Foram apresentadas no código as constantes “Math.PI” e “Math.E” que, conforme já mencionado, simplificam a utilização dos valores para π

94 JAVA com Orientação a Objetos

e ln. Porém, nem só de constantes vivem as operações matemáticas e para isso, a classe Math disponibiliza vários métodos que auxiliam nas mais di-versas operações. Entre os principais métodos ofertados pela classe, temos a comparação de valores maiores e menores, bem como operações como potên-cias e raízes para os cálculos de Trigonometria. Considerando isso, vamos à apresentação de métodos para uma comparação para o conhecimento de sua sintaxe.

// ComparaValores.java

public class CamparaValores {

public static void main(String[] args) {

���"�����������������

System.out.println(“O maior valor é “

+ Math.max(valores1[0], valores1[1]));

System.out.println(“O menor valor é “

+ Math.min(valores1[0], valores1[1]));

}

}

Verifique que no exemplo, foi realizada a comparação de valores, se-jam eles máximos, sejam mínimos por métodos da classe Math. Porém, a maioria dos métodos fornecidos pela classe Math auxilia na manipulação dos valores trigonométricos. Para verificarmos a utilização dos métodos da clas-se Math para a Trigonometria, nada mais interessante que utilizar o clássico exemplo da hipotenusa. Logo, transcreva o código e execute-o.

// Hipot.java

public class Hipot{

public static void main(String args[]) {

double p1 = 12;

double p2 = 16;

System.out.println(“A distancia entre os pontos é “

+ Math.hypot(p1, p2));

}

}

Capítulo 5 - Ferramentas úteis para o dia a dia 95

Outros métodos, como os que calculam o seno, cosseno e tangente, além de suas variações, são fornecidos pela classe Math. Finalizamos nossa análise sobre os métodos da classe Math com um dos mais utilizados e im-portantes, que é o “Math.random( )”. O método trabalha com valores randô-micos que variam de 0.0 até 1.0. Em geral, é necessária a manipulação de tais valores para se obter sua utilidade para a criação de aplicações do dia a dia, como podemos perceber no exemplo a seguir.

// NumeroRandomico.java

public class NumeroRandomico {

public static void main(String[] args) {

int valorMin = 0;

int valorMax = 10;

int ranger = valorMax - valorMin;

double valorRandomico;

for (int i = 0; i < 10; i++) {

valorRandomico = Math.random();

System.out.println(“O número entre”

+valorMin+” e “+valorMax+” é:”

+ Math.round(

valorMin + valorRandomico * ranger));

}

}

}

No exemplo, definimos os valores mínimos e máximos que definem o limite para os valores randômicos que queremos. Logo após, criamos uma variável que recebe o valor randômico. Finalizando, temos um laço de repe-tição, no qual realizamos o arredondamento da transformação dos valores fracionados. É importante mencionar que existem outros métodos da classe Math que podem ser utilizados para as operações matemáticas que agregam valor às suas aplicações.

5.4 Trabalho com vetores especiais

Como temos visto desde o início de nosso trabalho, a tecnologia Java

96 JAVA com Orientação a Objetos

se destaca claramente das outras devido à sua diversidade. Diante isso, outra ferramenta que deve ser mencionada, entre as diversas que a linguagem Java disponibiliza, consiste nas classes para o trabalho com vetores.

Em sua maioria, as diversas linguagens de programação disponíveis no mercado trabalham com vetores convencionais que delimitam um tamanho fixo. Isto é, impedem que estes sofram alteração de tamanho durante a exe-cução, como, por exemplo, os que foram desenvolvidos em nosso primeiro capítulo.

A linguagem Java fornece subsídios adicionais para a manipulação dos vetores, resolvendo problemas como o citado, no caso, a alteração de tama-nho durante a execução. Além disso, disponibiliza classes para as operações de nossos vetores estáticos. Isso tudo obviamente é feito por um conjunto de classes.

5.4.1 Classe Vector

Entre estas, temos a Vector, que possibilita a criação de uma estrutura de dados semelhante aos vetores convencionais, porém os objetos instan-ciados com a utilização dessa classe podem ser redimensionados dinamica-mente durante a execução. Logo, a qualquer momento, quando é necessário mais espaço para o armazenamento, o próprio sistema, por meio da máquina virtual, encarrega-se de dobrar o tamanho do espaço inicialmente alocado para o vetor, no caso, um objeto da classe Vector.

Pois bem, outra característica, que deve ser considerada e que torna a classe Vector diferenciada, está na capacidade de armazenar qualquer tipo de entidade, independentemente de seu tipo. Isto se dá devido ao fato da classe Vector fazer o armazenamento de referências para Object. Logo, como já sabemos, tudo no Java consiste nas classes que herdam de Object e isso, garante que possamos trabalhar com qualquer que seja o tipo do elemento a ser armazenado no vetor. Então, nada como a prática para entendermos melhor os conceitos apresentados. Vamos a eles.

// Classe ExemploVector.java

import java.util.Vector;

public class ExemploVector{

public static void main(String[] args){

Capítulo 5 - Ferramentas úteis para o dia a dia 97

Vector vetor = new Vector();

Carro mercedez = new Carro();

vetor.add(mercedez);

Bola bolaFutebol = new Bola();

vetor.add(bolaFutebol);

if(!vetor.isEmpty()){

for (int i = 0; i < vetor.size(); i++) {

Object object = vetor.elementAt(i);

}

System.out.println(vetor.size());

}

}

}

No exemplo anterior, um detalhe a ser observado está no fato de que, diferentemente dos vetores trabalhados até aqui, não definimos o tama-nho de nosso vetor para a variável ‘vetor’. Isso graças à capacidade da classe Vector que determina o tamanho a ser alocado durante a execução, sendo que isso é ideal para a manipulação de grandes vetores, bem como estruturas heterogêneas. Por ser uma classe, Vector disponibiliza para seus objetos, no caso, vetores especiais, funcionalidades que não são comuns aos vetores tra-dicionais, tais como, a verificação do tamanho do vetor ou mesmo se eles es-tão vazios, conforme foi apresentado no exemplo, através dos métodos size( ) e isEmpty( ).

Entretanto, isto não elimina um dos maiores problemas do trabalho com vetores, que é sua navegação e busca. Imagine um vetor que cresce e tem um tamanho de um milhão de posíções. No caso, isso tornaria o processo de busca computacionalmente inviável, já que para encontrar um elemento, seria necessário percorrer o vetor. Isto se torna mais crítico, caso o objeto procurado esteja no final do vetor.

Para solucionar esse problema, a linguagem Java fornece outra classe para o trabalho com vetores - a HashMap.

98 JAVA com Orientação a Objetos

5.4.2 Classe HashMap

Seu diferencial está no fato de que ela permite a associação de índices que identificam e tornam o objeto único dentro do vetor. Tal índice se torna uma chave para a recuperação do valor de maneira pontual. Isto garante que possa ser realizada uma consulta de um vetor de um para um. Obviamente, isto é bem diferente do que ocorria com a definição dos vetores estáticos vis-tos em nosso primeiro capítulo ou mesmo nos definidos com a classe Vector. Depois destas considerações, vamos a um exemplo com a classe HashMap.

// Classe NovoVetor.java

import java.util.HashMap;

public class NovoVetor{

public static void main(String[] args) {

HashMap pessoas = new HashMap();

Pessoa newPessoa = new Pessoa();

newPessoa.nome = "Fulano da Silva";

String chave = "Fulano";

pessoas.put(chave, newPessoa);

Pessoa outraPessoa = (Pessoa)pessoas.get(chave);

System.out.println("Nome recuperado: "+

outraPessoa.nome);

}

}

Note que no exemplo anterior, foi instanciado um objeto do tipo HashMap denominado pessoas, no caso um vetor, e por meio do método put( ), foi armazenado um objeto da classe Pessoa. Repare que foi necessária a atribuíção de uma chave para a identificação do objeto, que será utilizado em uma posterior recuperação. Isto, por sua vez, é feito com a utilização do método get( ) da classe HashMap, como visto no código anterior.

É importante ainda mencionar que o toolkit Java possui ainda uma classe que disponibiliza métodos para a realização de operações nos vetores. Essa classe não é denominada por acaso de Arrays.

Capítulo 5 - Ferramentas úteis para o dia a dia 99

5.4.3 Classe Arrays

A classe Arrays fornece suporte para as principais manipulações que um vetor pode sofrer, no caso a comparação, ordenação ou mesmo pesquisas binárias, além de outras. Para verificarmos o funcionamento da classe Array, transcreva o código e execute para verificar seu resultado.

// Classe ManipulandoArrays.javaimport java.util.Arrays;

public class ManipulandoArrays { public static void main(String[] args) { String[] nomes = new String[3]; nomes[0]= "Fulano"; nomes[1]= "Ciclano"; nomes[2]= "Beltrano"; Arrays.sort(nomes); for(int i=0;i<nomes.length;i++){ System.out.println(nomes[i]); } }

}

A classe Array, como pode ser observado, consiste em uma classe que manipula vetores estáticos. Além disso, é uma classe abstrata que não precisa ser instanciada para a utilização, sendo utilizada sua própria referência. Ela, como já dito, possui uma série de métodos, entre eles, provê o método sort( ) que foi utilizado no exemplo, responsável por ordenar o array passado como parâmetro, realizando internamente um mecanismo de comparação entre as strings e ordenando-as.

Note que utilizamos o atributo length para que a impressão ordenada dos nomes fosse realizada através da estrutura de repetição for. Isto abre espaço para que seja comentado que mesmo os vetores sendo estruturas es-táticas, estes possuem alguns atributos e métodos que auxiliam em sua ma-nipulação, como, por exemplo, o método equals( ).

Com isso, chegamos ao final de mais um capítulo. Nosso próximo com-promisso é a necessidade de trabalharmos com o tratamento de exceções no Java, o que nos abrirá caminho para elementos mais avançados, tais como, o trabalho com arquivos ou a manipulação de streams.

Capítulo 6

Tratamento de exceções e entrada de dados

���������������� ������������ ������ ����������� ����� ��-������ �� ��� ��������� ��� �� ������� ������� ��� �������������� ��� ������������� ���������� ������ �����������������������������������-��������� �������� �������������������������������!���� �������� ������ ���"������������������������������� ��������� �� ��������#����������-�$����#%��������&�������#�����#&���������������

'�� ��� ��� ��� �������� ������ ����� ��&� ������� ��� ���� ��� ����������������� ����������� ������������ �������������������$���� ����������� ��������������(�$������� �������������������(����$���������������)������ ������!���� ���*�����������������������-�$������������������������������� ��������������������#� �������������������������������������#������������ �������������� ��&� ���������� �$�������������������$�� ���������������������#�������-������ ����� �������������������� ���������������������#������������� ������������������������+������ ����!(��� ����������������-������%���������������������� ������,� ������������� �������������� �� �$��

/��������������������(������� ��� ������������������������-������������#������������� ������ ��������� ������������!�������-������������#��(�� ���������� �������������� �������+� �� �����!���&����������������011��������#���!���� ��������������� ��������������������� ����������� ��$�������������0�������������������������%�����(����������������������� �����$������ ��$��������� 23������������������$�� ���������� �����������������(�$������ �$��������������

Como mencionado, diversas classes fornecidas pelo JDK podem ser utilizadas para fornecer tal suporte para as aplicações desenvolvidas, diminuindo o tempo de possíveis manutenções que venham a ocorrer e au-mentando a capacidade dos programas em Java.

102 JAVA com Orientação a Objetos

6.1 Tratadores de exceções

A exceção na linguagem Java é uma indicação de que um erro ou um problema aconteceu durante a execução de uma aplicação. Isto se torna mais suscetível considerando que a linguagem Java fornece uma grande quantidade de bibliotecas, no caso, APIs, ou mesmo classes próprias. A ideia nem chega perto da perfeição, mas, ao menos, tenta garantir à tecnologia, que as classes de exceção tratem as situações de erros moderados que podem ser encontra-dos e visualizados em seus programas e, então, recuperados.

Uma maneira interessante de interpretar essas exceções é sempre tra-balhar os trechos de código que apresentam um grau maior de possibilidade de que um erro possa vir a acontecer e geralmente, isto está vinculado à utiliza-ção de recursos externos à tecnologia. Isto, em um contexto mais recente e atualizado, no qual os sistemas são construídos sem critérios, torna a tecno-logia Java um elemento diferenciado e um porto seguro para o desenvolvi-mento de soluções complexas na construção de aplicações críticas, tais como, sistemas hospitalares, de aviação e até mesmo espaciais e de robótica.

O tratamento de exceções no Java nada mais é que um processo de ga-tilho, que ao ser disparado um erro como mensagem para o sistema, possibi-lita que seja trabalhada a exceção. Este processo demonstra ao sistema o erro, além de relatá-lo para o entendimento e o tratamento da melhor solução para a recuperação e a continuídade das próximas rotinas do programa.

Assim, o tratamento de exceções geralmente deve ser utilizado ao:Processar situações excepcionais, nas quais um método seja incapaz de

terminar sua função por razões que fogem ao seu controle;Processar exceções de componentes que não estão projetados para re-

alizarem tais tarefas diretamente;Em projetos de grande porte para tratar as exceções de maneira uni-

forme em todo o projeto. A manipulação das exceções em Java é feita da mesma maneira como

na linguagem C++, com a utilização das claúsulas try e catch. A cláusula try é utilizada para indicar o trecho de código que será executado e no qual poderá ocorrer uma exceção, no caso, um pedaço de código onde a possibilidade de que possíveis erros ocorram é maior, tal como a abertura de um arquivo ou mesmo a abertura de uma conexão de rede com outro computador, e como já mencionado, a conexão com um banco de dados.

Capítulo 6 - Tratamento de exceções e entrada de dados 103

Já na declaração da cláusula catch, define-se o código a ser executa-do, caso algum erro ou, no caso, uma exceção venha a acontecer durante a execução da instrução principal, presente na cláusula try. O quadro abaixo demonstra a organização das cláusulas try/cath que devem ser utilizadas dentro do escopo de um programa Java.

...

try{

...

// trecho do código a ser executado

}catch(Classe que trata a excecao){

...

// tratamento da exceção

}

...

Um detalhe importante a ser considerado está na possibilidade de exis-tirem quantas cláusulas catch forem necessárias para o melhor desempenho da aplicação. Isto se deve ao fato de poderem existir vários tipos de possíveis exceções e obviamente, é interessante que exista um tratamento específico para cada um desses gargalos do que, por exemplo, apenas um tratamento generalista que possa vir a comprometer sua recuperação e continuídade na execução do programa.

Além disso, podem ocorrer situações nas quais é necessária a execução de alguma tarefa ou instrução, ocorrendo ou não uma falha no trecho de código principal, ou seja, com o perfeito funcionamento da aplicação ou não. Aqui, entra em cena a cláusula finally, na qual é definido o bloco de código que será executado havendo ou não o lançamento de uma exceção. Sua utili-zação deve ocorrer após a declaração das cláusulas try e catch. Assim, temos uma nova estrutura para o tratamento das exceções nos Java, como apresen-tado no trecho a seguir.

...

try{

...

// trecho de código a ser executado

104 JAVA com Orientação a Objetos

}catch(Classe que trata a excecao){

... // tratamento da exceção

}catch(Classe que trata a excecao){

...

// tratamento da exceção

��������

...

/*código a ser executado com ou sem

exceção */

}

...

Aqui, é necessário que façamos algumas considerações para entender-mos o tratamentos de exceções. Conforme você deve ter observado nos qua-dros, a cláusula catch obriga-nos a adotar uma classe que será responsável por tratar os possíveis erros que venham a ocorrer. As cláusulas vistas até aqui de nada serviriam se não existissem classes responsáveis pela identificação dos erros lançados pela JVM, além de possuir métodos que possibilitem o enten-dimento do problema e dos elementos para a sua recuperação. Existem algu-mas classes que devem ser conhecidas para a sua manipulação, em conjunto com as cláusulas para tratar as exceções mais comuns, sendo apresentadas na Tabela 6.

Tabela 6. Principais exceções.

Classe Função

ArithmeticException

Classe utilizada para tratar as exceções em operações aritméticas e lança uma exceção quando estas são impossíveis de ser realizadas.

NullPointerException Utilizada para o controle de instâncias e ocorre quando um objeto é instanciado.

Capítulo 6 - Tratamento de exceções e entrada de dados 105

NegativeArraySizeExceptionClasse utilizada para o controle de vetores e ocorre quando um valor nulo é atribuído a uma posição do array.

ArrayIndexOutOfBoundsExceptionUtilizada para o controle de vetores e ocorre quando se tenta acessar uma posi-ção do array que não existe.

IOExceptionUtilizada para tratar as exceções nas ope-rações de entrada e saída de dados.

Exception

Classe geral para o tratamento de exce-ções, ou seja, qualquer que seja o erro. Além disso, utilizada pelas demais classes que tratam os erros por meio da herança.

Bom pessoal, assim como qualquer classe, as de exceção devem ser im-portadas para a utilização dentro de um programa. Como feito nos demais capítulos trabalhados até aqui, nada como implementar alguns exemplos para a fixação dos novos e essenciais conceitos da linguagem Java vistos em nosso sexto capítulo. Assim, transcreva o código observando a utilização das cláusulas para o tratamento de exceções, então ao final, execute o programa para visualizar o resultado.

// Classe Excecao.java

public class Excecao{

public static void main(String[] args){

int a = 20;

int b = 0;

int c = 0;

try{

c = a/b;

}catch(ArithmeticException e){

System.out.println(“Problemas na operação”);

System.out.println(e); }�������

106 JAVA com Orientação a Objetos

$��������!�����&��!���YZ������?�����' } }

}

No exemplo apresentado, foi criado um programa que contém um problema matemático, com a divisão por 0. Assim, obrigamos que a cláusula catch seja executada. Verifique que todas as informações necessárias para o entendimento do problema são disponibilizadas pela instância da classe ArithmeticException. Além disso, a cláusula finally é executada ao final do programa com o lançamento da exceção.

Nos últimos anos, várias tecnologias têm contribuído para o avanço da tecnologia Java, tornando-a mais interessante em diversos aspectos, incluin-do também o tratamento de exceções. Um novo conceito que vem ganhando espaço é a Programação Orientada a Aspectos. A orientação a aspectos é um paradigma de programação que vem sendo desenvolvido para somar valor à POO (Programação Orientada a Objetos) e assim, tornar todo o processo de programação mais eficiente. Fica a dica de uma leitura complementar sobre a Programação Orientada a Aspectos, que é algo facilmente encontrado na Web.

Outro detalhe sobre o tratamento de exceções que deve ser comentado é que a tecnologia Java permite outra forma de realizar o tratamento. Este consiste na utilização da cláusula throws.

6.1.1 Throws

Assim como nas cláusulas try/catch, a throws é a responsável por tra-tar os possíveis erros que venham a acontecer, porém a cláusula throws exige que sejam listadas as classes que tratam as possíveis exceções que podem ser disparadas na assinatura de um método. Para ter uma melhor compreensão, vamos à sintaxe da cláusula throws.

...

tipoDeRetorno nomeDoMetodo() throws ClasseDeExcecao1,

ClasseDeExcecao2, ...{

// corpo do método

}

...

Capítulo 6 - Tratamento de exceções e entrada de dados 107

Aqui, cabe dizer que a única diferença entre as duas sintaxes apresen-tadas é que as cláusulas try/catch definem seu bloco de código que será tra-tado, caso ocorra alguma exceção. A cláusula throws, por sua vez, é sempre definida para um método de uma classe, logo, a qualquer momento dentro do método ao ocorrer um erro, as classes definidas são executadas para tratá-lo. Vamos a um exemplo para o conceito apresentado.

// Classe ExcecaoThrows.java

public class ExcecaoThrows{

public static String divisao(int a, int b)throws

ArithmeticException{

return “O valor da divisão é “ + a/b;

}

public static void main(String[] args){

int a = 20;

int b = 0;

int c = 0;

divisao(a,b);

}

}

Bom, conforme mencionado, o método de divisão da classe ExcecaoThrows.java utiliza a palavra reservada throws para invocar a clas-se ArithmeticException para realizar o tratamento do erro matemático. Com o conhecimento adquirido para o tratamento de erros, abrimos espaço para também apresentarmos uma nova maneira de obter os dados oriun-dos do teclado, que é por meio da utilização das classes BufferedReader e InputStream.

6.2 Entrada de dados

Conforme você já deve ter percebido, o método apresentado, e que você conhece desde o início da leitura de nosso livro, no qual utilizamos ob-jetos da classe Scanner, possui suas limitações,.além de ser instável e inviável para as grandes quantidades de dados digitados. Pois bem, agora iremos veri-ficar uma nova forma de realizar a manipulação dos dados vindos do teclado.

108 JAVA com Orientação a Objetos

Como já foi mencionado no início de nosso livro, a classe System é res-ponsável por controlar todas as funções do sistema. E por meio de System.in, estamos lidando diretamente com as entradas de dados. Até aqui, nenhuma novidade. Porém, existem outras classes que substituem a classe Scanner na manipulação dos dados, no caso, InputStream e BufferedReader. A primeira é reponsável pela leitura do fluxo de entrada. A segunda, pela manutenção no buffer dos dados que foram digitados até que seja pressionada a tecla Enter. Pois bem, para que você possa compreender e verificar o funcionamento des-sa modalidade de entrada de dados, vamos a um exemplo.

// ManipulacaoDados.java

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStreamReader;

public class ManipulacaoDados {

public static void main(String args[]){

String dados = new String();

BufferedReader entr = new BufferedReader(

new InputStreamReader(System.in));

try {

System.out.println(“Entre com a sua frase:”);

dados = entr.readLine();

System.out.println(“A frase digitada foi:”+dados);

} catch (IOException e){

System.out.println(“Erro ao ler string”);

e.printStackTrace();

}

}

}

Você deve estar perguntando: Mas, por que isso não foi apresentado antes? No caso, esta metodologia de entrada de dados não foi demonstrada anterioremente, pois necessitava do tratamento de exceções, uma vez que estamos lidando com alguns elementos critícos, tais como, a manipulação de streams, buffer, e isso nos força a lidar com um tratamento prévio dos riscos que podem ser impostos à nossa aplicação.

Capítulo 6 - Tratamento de exceções e entrada de dados 109

Entendendo o que foi feito em nosso exemplo, verifique que inicial-mente foi declarada uma variável de dados do tipo String, que receberá os valores oriundos do teclado. Para isso, no entanto, foi necessária a utiliza-ção dos objetos da classe BufferedReader e InputStream. A primeira, como mencionado, apenas armazena os dados oriundos do teclado, obtidos por meio da InputStrem, que é responsável por recuperar os dados de entrada do sistema, no caso, o teclado, por meio de System.in. O método readLine( ), do objeto da classe BufferedReader, faz com que o sistema passe a esperar a entrada de dados e armazená-los na memória durante a execução.

Encerrando este capítulo, vale resaltar que as duas classes citadas nes-ta seção também são úteis para a manipulação de arquivos, característica essa que consideraremos em nosso próximo capítulo.

Capítulo 7 Manipulação de arquivos de texto

Bom pessoal, chegamos ao nosso último capítulo e para finalizarmos os conceitos e as tecnologias introdutórias da tecnologia Java, nada como aprendermos a criar, realizar a entrada e a leitura de dados nos arquivos tex-to. Os conceitos trabalhados até aqui nos demais capítulos serão essenciais para uma melhor compreensão dos conceitos relacionados ao trabalho com arquivos, principalmente os referentes ao tratamento de exceções, conside-rados no capítulo anterior.

Estudar a manipulação de arquivos é de extrema importância, pois geralmente todas as aplicações trabalham com algum tipo de persistência de dados, uma vez que todos os exemplos realizados e apresentados até aqui somente fazem uso da memória volátil de seu computador. Ou seja, todos os dados são perdidos assim que finalizamos nossa aplicação, como você já deve ter percebido.

Diante de tais fatos, a maneira mais básica e simples de realizar a per-sistência dos dados é por meio da utilização de arquivos. Isso possibilita que as informações das aplicações possam ser recuperadas após sua finalização, abrindo novas possibilidades para seus programas. Obviamente, existem formas mais profissionais de manter os dados, como, por exemplo, a utiliza-ção de Sistemas Gerenciadores de Banco de Dados (SGBD), mas, em diversos momentos, a manipulação de arquivos é útil e interessante, mantendo, na maioria das vezes, neutralidade dos dados. Neste primeiro livro, não iremos abordar a manipulação do banco de dados, uma vez que o objetivo aqui é fazer com que este livro seja um referencial para as disciplinas introdutórias de programação.

A tecnologia Java fornece diversas classes e com isso, formas para o trabalho com arquivos, no caso, a criação, armazenamento e recuperação de dados. Então, vamos apreciá-las.

7.1 Arquivos

A primeira coisa que devemos tratar sobre a manipulação de arquivos

112 JAVA com Orientação a Objetos

com Java é a oferta de um pacote destinado a manipulá-los, denominado java.io. É esse pacote que mantém a maioria das classes que podem ser utili-zadas para o trabalho com arquivos.

Um detalhe importante que deve ser mencionado é que, em sua maio-ria, os programadores tratam a leitura e a escrita, respectivamente, como operações de entrada e saída de dados em um arquivo. Tal notação é uma formalização do processo e também é comum em outras linguagens de pro-gramação, tais como C e C++. Além disso, a notação apresentada demonstra uma relação do ponto de vista da aplicação, na qual o arquivo a ser lido passa ser uma fonte de entrada de dados a serem processados e depois, saindo da aplicação, eles são escritos e mantidos novamente no arquivo.

O java.io é um dos pacotes mais extensos da tecnologia Java, com mais de 50 classes que fornecem suporte para o trabalho com arquivos, além de funcionalidades como, por exemplo, a compactação de arquivos, mas, em sua maioria, tais classes são classificadas nos dois grandes grupos já men-cionados, no caso, a entrada e a saída de dados. É importante mencionar que as operações irão depender do tratamento de exceções para a realização da manipulação dos arquivos. Geralmente, para estes casos, é utilizada a classe IOException que também faz parte do pacote java.io e traz funcionalidades que auxiliam na recuperação dos erros que possam vir a acontecer.

Outro importante detalhe a ser mencionado sobre o pacote java.io é o fato de que as classes oferecidas permitem também o trabalho com arqui-vos especiais como binários, de buffer, como vimos no capítulo anterior, ou mesmo stream de vídeo e som. Aqui, não iremos considerar tais classes, mas uma boa gama deste material pode ser encontrada na Web. Diante de tantas possibilidades, é necessário que façamos uma seleção das principais para que concentremos nossos esforços. No caso, estaremos trabalhando com FileReader, Scanner, PrintWriter, FileInputStream, FileOutputStream, RandomAccessFile e IOException.

7.2 Entradas

Indo ao que realmente interessa, no caso, a leitura de dados em arqui-vos, que é considerada uma forma de entrada de dados para uma aplicação, a linguagem Java fornece uma classe que possibilita este processo - a FileReader. Sua utilização não apresenta nada fora do normal das demais classes consi-deradas até aqui. Assim, devemos realizar a criação de um objeto da FileReader

Capítulo 7 - Manipulação de arquivos de texto 113

que fornece atributos e métodos para manipulação do arquivo. Entretanto, a classe FileReader necessita da utilização de uma classe

já conhecida para realizar o acesso e a manipulação dos dados vindos do ar-quivo. Essa classe consiste na Scanner, classe com a qual já trabalhamos no início de nosso livro. Pois bem, se você lembra, a Scanner é responsável por auxiliar na manipulação dos dados que vêm do teclado, acessando o atributo de entrada de dados da System.in. Em nosso caso, só mudaremos a fonte dos dados, que antigamente consistia no teclado e agora, é o arquivo.

Iremos, agora, utilizar a classe Scanner para realizar operações no obje-to da classe FileReader, que faz referência ao local onde se encontra o arquivo de texto. Nada como um bom exemplo para entender o processo. Transcreva o código abaixo e execute-o para verificar seu funcionamento.

// LerArquivo.java

import java.io.IOException;

import java.io.FileReader;

import java.util.Scanner;

public class LerArquivo{

public static void main(String[] args) {

FileReader arq = null;

try {

arq = new FileReader(

"c:\\programas\\Arquivo.txt");

} catch (IOException e) {

e.printStackTrace();

}

Scanner leitor = new Scanner(arq);

while(leitor.hasNextLine()){

String linha = leitor.nextLine();

System.out.println(linha);

}

}

}

114 JAVA com Orientação a Objetos

É bom mencionar que, para nosso programa funcionar, o arquivo ao qual fizemos a referência com o objeto da classe FileReader deve estar no mesmo local onde a classe se encontra. Uma forma de resolver este problema é passando o caminho de referência completo para o local no qual o arquivo se encontra, no caso, “C:\programas\Arquivo.txt”. É importante citar que foi necessária a realização do tratamento de exceção que possa vir a acontecer, como, por exemplo, o fato do arquivo não ser localizado. Isso obviamente foi realizado com a utilização das cláusulas try/catch, além da classe IOException. Ainda em nosso exemplo, um objeto da classe Scanner foi instanciado, sen-do passada, como parâmetro, a instância da classe FileReader, denominada arq, que define o caminho do arquivo, como já analisado. Após, é utilizada a estrutura de repetição while para a leitura linha a linha do arquivo e uma posterior impressão do conteúdo.

Conforme vimos, a manipulação de arquivos no Java trata-se de uma rotina simples, sem muitos segredos, isso graças ao suporte que a tecnolo-gia fornece. Entretanto, vale ressaltar que tais funcionalidades dependem da correta utilização das classes do pacote java.oi. Apresentado o conceito de en-trada de dados, ou seja, a leitura de um arquivo, vamos ao processo de criação e escrita ou, conforme já é de seu conhecimento, à saída de dados utilizando a classe PrintWriter do pacote java.io.

7.3 Saídas

Após verificarmos como funciona o processo de entrada de dados, ire-mos trabalhar com a criação e a gravação de dados em um arquivo no for-mato de texto, utilizando para isso, a classe PrintWriter. Tal classe fornece atributos e métodos para a manipulação de arquivos, entretanto, aqui tam-bém é necessária a utilização da classe IOException para o tratamento das exceções, assim como é feito para a leitura de dados. Mas aqui, trataremos os erros que venham a ocorrer no processo de criação e escrita dos dados.

Vamos colocar a mão na massa e escrever mais um exemplo. Neste caso, um no qual iremos criar um arquivo e escrever uma mensagem dentro deste.

// EscreverArquivo.java

import java.io.IOException;

import java.io.PrintWriter;

Capítulo 7 - Manipulação de arquivos de texto 115

public class EscreverArquivo{

public static void main(String[] args) {

PrintWriter arq = null;

try {

arq=new PrintWriter("dados.txt");

arq.println("Mensagem escrita");

arq.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

Vários detalhes devem ser mencionados sobre o processo de criação e escrita em arquivos. Inicialmente, um importante detalhe a ser descrito, e que você deve levar em consideração sobre a criação e a escrita, é que se seu arquivo já existir, ele será recriado e com isso, todos os dados existentes ante-riormente serão perdidos. Outro detalhe é que para que todos os dados sejam persistidos em um arquivo, é necessário que sempre ao final do processo de escrita, ou seja, ao final da utilização da instância da classe PrintWriter, seja feita a invocação do método close( ). Tal processo pode ser contemplado no exemplo anterior. Finalmente, no programa anterior, note que foi utilizado para a escrita do conteúdo, o método println( ), também da classe PrintWriter.

Então, vamos tornar nosso exemplo mais interessante. Para isso, iremos, com a utilização da classe Scanner, capturar os dados do teclado e persisti-los em um arquivo. Este será nomeado com o nome definido pelo usuário. Então, transcreva o código e execute-o para verificar seu adequado funcionamento.

// CriandoArquivo.java

import java.io.IOException;

import java.io.PrintWriter;

import java.util.Scanner;

public class CriandoArquivo{

public static void main(String[] args) {

116 JAVA com Orientação a Objetos

Scanner entrada=new Scanner(System.in);

PrintWriter arq = null;

System.out.println("Nome do arquivo");

String nome = entrada.nextLine();

System.out.println("Entre com os dados");

String dados = entrada.nextLine();

try {

arq = new PrintWriter(nome);

} catch (IOException e) {

e.printStackTrace();

}

arq.println(dados);

arq.close();

}

}

Note que no exemplo, por meio do operador new e o construtor da classe PrintWriter, foi passado o nome do arquivo a ser criado. Entretanto, esse arquivo só será efetivamente criado após a execução do método close( ), ou seja, ao finalizar o programa. Com isso, verificamos o processo de criação e escrita em arquivos, sendo algo bem mecânico.

7.4 Streams

Outra possibilidade de trabalhar com a manipulação de entrada e saída de dados consiste na utilização das classes FileInputStream e FileOutputStream. Essas classes são extremamente úteis, pois nem só de arquivos com texto natural vivem nossos programas. Estas são úteis para as manipulações de todos os tipos de arquivos. Assim como nas demais classes vistas até aqui, a FileInputStream e a FileOutputStream são fornecidas pelo pacote java.io. Elas são utilizadas para manipular fluxos de bytes, ou seja, possibilita uma manipulação em um nível mais baixo. Estes dados, na maioria das vezes, se alterados, comprometem sua estrutura e possível utilização. Ou seja, para uma manipulação mais segura e da qual dependemos de uma maior seguran-ça, as classes são recomendadas.

Como os próprios nomes sugerem, a FileInputStream é utilizada para a entrada de dados e a FileOutputStream, para a saída. Um aspecto

Capítulo 7 - Manipulação de arquivos de texto 117

importante a ser colocado aqui é o fato de que assim como nas classes FileReader e PrintWriter, já vistas, para as classes que auxiliam na manipulação de streams também é necessária a utilização do tratamento de exceção. Para ter uma melhor compreensão do que foi considerado, veja o exemplo a seguir e execute-o.

// Classe ExemploStream.java

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.IOException;

public class ExemploStream{

public static void main(String[] args) {

FileOutputStream saida = null;

FileInputStream entrada = null;

try {

saida = new FileOutputStream(“dados.txt”);

saida.write(1010);

entrada= new FileInputStream(“dados.txt”);

System.out.print(entrada.read());

} catch (IOException e) {

e.printStackTrace();

}

}

}

No exemplo anterior, foi criado um arquivo e escrita uma linha de stream com a utilização do método write( ) da classe FileOutputStream. Logo após, é realizada a leitura dos dados escritos e a impressão destes por meio do método read( ) da classe FileInputStream. Repare que o processo de cria- o processo de cria-ção dos objetos para a manipulação dos arquivos de stream é semelhante aos realizados até aqui com outras classes pertencentes ao pacote java.io.

118 JAVA com Orientação a Objetos

7.5 Acessos aleatórios em arquivos

Em todos os exemplos apresentados até aqui, toda a leitura é realizada de maneira sequencial, ou seja, do início do arquivo até seu fim, sempre nessa ordem. No entanto, em diversas situações, assim como no caso dos vetores, isso pode ser caro computacionalmente. Imagine que você esteja buscando uma informação em um arquivo extenso e essa informação esteja apenas no final do arquivo. Pois bem, para que você chegue a essa informação, deve percorrer todo o arquivo. Isso muitas vezes complica todo o processo. No caso, é muito mais econômico computacionalmente realizar a leitura de uma posição especifica no arquivo ou mesmo a escrita em determinado ponto. Para isso, a tecnologia Java fornece a classe RandomAccessFile, que possibilita o trabalho de acesso aleatório a posições dentro dos arquivos. A RandomAccessFile é mais uma classe que também faz parte do pacote java.io.

Bom, neste caso, a vantagem de manipular seus arquivos com as ins-tâncias dessa classe é nítida, indo pontualmente no local no qual se dese-ja escrever ou ler. Para tanto, são utilizados métodos para as operações nos arquivos, tais como seek( ), length( ), read( ) e write( ), entre os principais. Aqui, oriento que o exemplo seja transcrito e executado.

// Aleatorio.java

import java.io.IOException;

import java.io.RandomAccessFile;

public class Aleatorio{

public static void main(String[] args) {

try {

������~����������������������~���������&

“dados.txt”,”rw”);

��������&�'

$��������!���&��������&''

} catch (IOException e) {

e.printStackTrace();

}

}

}

Capítulo 7 - Manipulação de arquivos de texto 119

Alguns aspectos do código anterior devem ter chamado a sua atenção. No caso, a classe RandomAccessFile trabalha com o conceito de definição do tipo e acesso, sendo que tal definição é realizada no momento da instancia-ção do objeto com a utilização de seu construtor. Obviamente, são utilizados parâmetros no momento da abertura do arquivo para a definição das permis-sões no arquivo. Os tipos de acesso que podem ser trabalhados consistem, respectivamente, nos atributos ‘r’ e ‘rw’, que indicam que o arquivo deve ser aberto somente para a leitura e quando podem ser realizadas operações tan-to de leitura quanto de escrita, respectivamente.

Para o posicionamento do cursor no arquivo na posição na qual se deseja realizar a escrita ou a leitura, é necessária a utilização do método seek( ). Para a leitura, continuamos a trabalhar com o método read( ), con-forme demonstrado no exemplo. Da mesma forma, podemos realizar a es-crita, sendo que para isso, utilizamos o método write( ) da própria classe RandomAccessFile.

Aqui, entretanto, é importante mencionar que existem diversas ver-tentes do método write permitindo que sejam trabalhados vários tipos de dados disponibilizados pela tecnologia Java. Existem métodos, tais como writeInt( ), writeBoolean( ) e writeChars( ), que possibilitam o tratamento de cada tipo de dado. Isso auxilia o desenvolvedor, pois evita que seja perdido tempo realizando sua conversão ou mesmo manipulação para persistir os da-dos. Para visualizar o resultado destas operações, altere o exemplo anterior conforme é demonstrado a seguir.

// Classe Aleatorio.java

import java.io.IOException;

import java.io.RandomAccessFile;

public class Aleatorio{

public static void main(String[] args) {

try {

������~����������������������~���������&

“dados.txt”,”rw”);

��������&�'

$��������!���&��������&''

�������������&�`������'

���������&'

120 JAVA com Orientação a Objetos

} catch (IOException e) {

e.printStackTrace();

}

}

}

No caso em específico, a estrutura continua a mesma e deve ser reali-zado o tratamento de exceções, já que sua manipulação pode acarretar pro-blemas para a aplicação.

Caro amigo, assim finalizamos nossa leitura. Espero que este manus-crito tenha sido de proveito para que você entenda os detalhes e os conceitos básicos da programação baseada na tecnologia Java, principalmente os vin-culados ao paradigma da programação orientada a objetos. Obviamente que a tecnologia não se restringe somente aos tópicos mencionados até aqui. Po-deríamos citar a criação de aplicações desktop com a utilização da API Swing, além do acesso ao banco de dados com a JDBC (Java Database Connection) ou ainda a criação de programas para dispositivos móveis ou Web, tudo ba-seado no Java.

Mas, obviamente que minha intenção até aqui sempre foi garantir que fossem apresentados os elementos que possam subsidiar o conhecimento dessas novas ferramentas que estão à sua disposição. Sinceramente, desejo--lhe sucesso nos seus desafios e espero revê-lo em breve.

Referências

Bibliográficas

BOENTE, Alfredo. Aprendendo a Programar em Java 2: Orientado a Objetos. Rio de Janeiro: Brasport, 2003.

ANSELMO, Fernando. Aplicando Lógica Orientada a Objetos em Java. 2. ed. Florianópolis: Visual Books, 2005.

CARDOSO, Caíque. Orientação a Objetos na Prática: Aprendendo Orientação a Objetos com Java. Rio de Janeiro: Ciência Moderna, 2006.

DEITEL, Harvey M. Java: Como Programar. 6ª ed. São Paulo: Pearson Prentice Hall, 2005.

SANTOS, Rafael. Introdução à Programação Orientada a Objetos Usando Java. Rio de Janeiro: Campus, 2003.

PUGA, Sandra; RISSETTI, Gerson. Lógica de Programação e Estrutu-ras de Dados: com Aplicações em Java. São Paulo: Pearson Prentice Hall, 2004.

Horstmann, Cay; Cornell, Gary. Core Java, Volume 1 – Fundamentos. 8 Edição. São Paulo: Pearson, 2010.

Block, Joshua. Java Efetivo - 2ª Edição. Rio de Janeiro: Alta Books, 2008.

Furgeri, Sergio. Java 7 - Ensino Didático. São Paulo: Editora Érica, 2010.

Sierra, Kathy; Bates, Bert. Use a Cabeça Java. Rio de Janeiro: Alta Books, 2005.

Apêndice IInstalação do Sdk e Configuração das Variáveis de

Ambiente (Windows Xp)

Para o download do JDK, siga os seguintes passos:

1. Acesse por meio de um navegador o endereço: http://java.oracle.com

2. Após acessar o endereço, clique no link Java SE em “Downloads” ou em “Top downloads”.

3. Logo em seguida, clique no botão “Java Platform” para selecionar a versão “Standard Edition” da tecnologia.

4. Após isso, aceite o termo e selecione o tipo de Sistema Operacional no qual a tecnologia será executada. No caso do Windows, selecio-ne conforme apresentado a seguir.

124 JAVA com Orientação a Objetos

5. Caso tudo tenha ocorrido conforme o esperado, será aberta a jane-la para o download do arquivo.

6. Depois, basta seguir as orientações do software no momento de sua instalação.

Para as variáveis de ambiente, siga os seguintes passos: 1. Selecione Iniciar > Painel de Controle > Sistema.

Apêndice I 125

2. Selecione Avançado > Variáveis de Ambiente.

3. Clique em Nova.

126 JAVA com Orientação a Objetos

4. Em “Nome da Variável”, digite JAVA_HOME.5. Em “Valor da Variável”, digite o caminho onde foi instalado o

Java em seu computador. Copie o caminho literalmente como é exibido, por exemplo, no Explorer.

6. Clique em OK.

7. Procure a variável PATH, selecione-a e escolha “Editar”.

Apêndice I 127

8. Em “Valor da Variável”, acrescente ao valor já existente em seu final: “;%JAVA_HOME%\bin”.

9. Clique em OK.

10. Selecione Avançado > Variáveis de Ambiente > Nova, assim como foi feito para a criação da variável JAVA_HOME. Se estiver em dúvida, observe o processo feito anteriormente.

11. Em “Nome da Variável”, digite CLASSPATH. 12. Em “Valor da Variável”, digite “.;%JAVA_HOME%\lib\tools.jar”.

13. Clique em OK. 14. Clique novamente em OK.

Para que você tenha certeza dos efeitos das mudanças, reinicie o sistema.

Apêndice IIJAVADOC

1. Inicialmente, é necessário realizar o comentário de documentação em sua classe definindo e seguindo os elementos definidos pela tecnologia Java. Existem diversas tags especiais definidas pela tecnologia, que auxiliam na definição de informações importantes e na formatação padrão, tais como, @author, @see e @return. Veja o exemplo:

/**

��������������������������������

* @see java.lang.Object

* @author Alex Coelho

*/

public class Carro{

public String cor;

public String marca;

public String modelo;

/**

* Construtor Carro

* @param Carro

* @throws Sem Exceções

*/

public Carro(Carro novo){

this.cor = novo.cor;

this.marca = novo.marca;

this.modelo = novo.modelo;

}

/**

* Método andar que imprime

* o valor String na tela

* @see java.lang.String

130 JAVA com Orientação a Objetos

*/

protected void andar(){

ligar();

System.out.println(“Carro andando”);

}

/**

* Método parar que imprime

* o valor String na tela

* @see java.lang.String

*/

protected void parar(){

System.out.println(“Carro parado”);

}

/**

* Método ligar que imprime

* o valor String na tela

* @see java.lang.String

*/

private void ligar(){

System.out.println(“Carro ligado”);

}

}

2. Feitos os comentários necessários, digite o comando javadoc em seu prompt de comando para sua classe, como segue o exemplo:

javadoc NomeDaClasse.java

Veja o funcionamento:

Apêndice II 131

Se tudo correu conforme o esperado, você deve ter acesso a uma pági-na html na mesma pasta onde se encontra sua classe, como é demonstrado a seguir.

É importante mencionar que a maioria das IDEs disponíveis no mer-cado possui algum tipo de suporte para agilizar e garantir a documentação com Javadoc.

Para obter maiores informações, acesse:http://www.oracle.com/technetwork/java/javase/documentation/

index.html.

À venda nas melhores livrarias.

Java na Web

A complexidade e o crescimento da Internet fez com que surgissem vários modelos e propostas para a comunicação entre aplicações e que esses fossem apresentados como opções de computação distribuída. Este livro aborda as principais tecnologias da plataforma Java 2 Enterprise ������������ �����������������������������������������������������������-�������� �!�� ������������ ����� "������ ��� �������� !����� ��������� �������� ����������������!��!��������������#����������������������$����%������������-�&������'������������'������������'�%�����������������(�������������������vêm se tornando uma das mais bem sucedidas para desenvolvimento em am-biente Web.)� �'��� ������� ���'*�� +,�� +��!����� �/�� +0/�� �!�1������ 314�� �������� ��������!��!��������������������������������5���������*�����������������6��7�8�'������(����9�!�����:�';�������*��<���������������������������'���!���������=����������>�������������������������������������$�������<�����������-sentados.

Impressão e acabamento<=>?@B�FB�GFHJK=B��HLM@HB��KFN=MB��JFB�

Tel: (21) 2201-6662