Conceitos JAVA Prof. Danton Cavalcanti Franco Junior http://www.dantonjr.com.br [email protected] Versão 1.0 Julho, 2007 Prof. Danton Cavalcanti Franco Junior – [email protected] – http://www.dantonjr.com.br 1. Iniciando Capítulo introdutório. História do Java e suas características de aplicabilidade e funcionamento. 1.1. Onde Encontrar o Java Os arquivos que compõem o Java: Compilador Java. Máquina Virtual Java – Java Virtual Machine (JVM). Documentação. Podem ser baixados na página da Sun: http://java.sun.com 1.2. O que é Java? Java tem a aparência de C ou de C++, embora a filosofia da linguagem seja diferente, também possui características herdadas de muitas outras linguagens de programação: Objective-C, Smalltalk, Eiffel, Modula-3, etc., muitas das características desta linguagem não são totalmente novas. Java é uma linguagem de programação orientada a objetos desenvolvida pela Sun Microsystems. Modelada depois de C++, a linguagem Java foi projetada para ser pequena, simples e portável a todas as plataformas e sistemas operacionais, tanto o código fonte como os binários. Esta portabilidade é obtida pelo fato da linguagem ser interpretada, ou seja, o compilador gera um código independente de máquina chamado byte-code. No momento da execução este byte-code é interpretado por uma máquina virtual instalado na máquina. Para portar Java para uma arquitetura hadware específica, basta instalar a máquina virtual (interpretador). Além de ser integrada à Internet, Java também é uma excelente linguagem para desenvolvimento de aplicações em geral. Dá suporte ao desenvolvimento de software em larga escala. 1.3. Histórico da linguagem Java Em 1991, um pequeno grupo de funcionários da Sun mudou-se para a San Hill Road, uma empresa filial. O grupo estava iniciando um projeto chamado “Projeto Green”, que consistia na criação de tecnologias modernas de software para empresas eletrônicas de consumo. Logo o grupo percebeu que não poderia ficar preso às plataformas, pois os clientes não estavam interessados no tipo de processador que estavam utilizando, e fazer uma versão do projeto para cada tipo de sistema seria suicídio. Desenvolveram então o sistema operacional GreenOS, com a linguagem de programação Oak. Em 1993 surgiu uma oportunidade para o “grupo Green”, agora incorporado como FirstPerson: a Time-Warner, uma empresa que estava solicitando propostas de sistemas operacionais de decodificadores e tecnologias de video-on-demand1. Isso foi na mesma época em que o NCSA lançou o MOSAIC 1.0, o primeiro navegador gráfico para Web. A FirstPerson apostou nos testes de TV da Time-Warner, mas esta empresa preferiu optar pela tecnologia oferecida pela Silicon Graphics. Depois de mais um fracasso de acordo com a 3DO a FirstPerson dissolveu-se, e metade do pessoal foi trabalhar para a Sun Interactive com servidores digitais de vídeo. Entretanto, a equipe restante continuou os trabalhos do projeto na Sun. Como a equipe de desenvolvimento tomava muito café enquanto estava trabalhando, foram ingeridas centenas de xícaras de café 2 até que o projeto estivesse pronto. Finalmente em maio de 1995 a Sun anunciou um ambiente denominado Java, homenagem às xícaras de café, que obteve sucesso graças à incorporação deste ambiente a browsers populares como o Netscape Navigator e padrões tridimensionais como o VRML3. A Sun considera o sucesso do Java na Internet como sendo o primeiro passo para utilizá-lo em decodificadores da televisão interativa, em dispositivos portáteis e outros produtos eletrônicos de consumo – exatamente como o Java tinha começado em 1991. Sua natureza portátil e o projeto robusto permitem o desenvolvimento para múltiplas plataformas, em ambientes tão exigentes como os da eletrônica de consumo. 1 Conceito de TV a cabo na qual você não espera a hora da programação da emissora. Você mesmo determina qual programa que quer ver no momento; ou seja, toda a programação está disponível a qualquer momento. 2 Java é a gíria para café nos EUA, assim como BomBril no Brasil; esta gíria foi criada quando a importação de café para o país provinha principalmente da Indonésia. O nove Java é o nome de uma ilha vulcânica da Indonésia. 3 VRML – Virtual Reality Modeling Language (Linguagem de Modelagem para Realidade Virtual), é um padrão de aplicativos de realidade virtual utilizado na Internet. Por meio desta linguagem escrita em modo texto, é possível criar objetos tridimensionais podendo definir cor, transparência, brilho, textura (associando-a a um bitmap). Os objetos podem ser formas básicas, como esferas, cubos, ovóides, hexaedros, cones, cilindros, ou formas criadas pelo próprio programador, como as extrusões. Apostila de Java Página 2 de 25 Prof. Danton Cavalcanti Franco Junior – [email protected] – http://www.dantonjr.com.br 1.4. Características do Java Podemos citar como características: Facilidade: a linguagem é derivada da linguagem C e C++, sendo assim familiar. Além disso, o ambiente retira do programador a responsabilidade de gerenciar a memória e os ponteiros. Portabilidade: por ser uma linguagem interpretada, o Java pode ser executado em qualquer plataforma ou equipamento que possua um interpretador Java (máquina virtual), e que tenha sido especialmente compilado para o sistema a ser utilizado. Robustez: os recursos da linguagem e do ambiente para o tempo de execução garantem que o código não derrube o sistema de alguém que “tropece” em uma homepage contendo uma animação, por exemplo. Segurança: além de proteger o sistema do cliente contra possíveis ataques não-intencionais, o ambiente também deve proteger contra ações premeditadas. Muito tempo e esforço dos desenvolvedores de Java estão sendo aplicados para que a linguagem se desenvolva nesse sentido. Orientação a Objetos: Java é uma linguagem totalmente orientada a objetos, o que permite a herança e a reutilização de códigos de forma dinâmica e estática, facilitando o dinamismo durante a manutenção de programas. Dinamismo: por ter um projeto orientado a objetos, o dinamismo faz parte da natureza do Java, o que permite a extensibilidade durante a execução. Alto Desempenho: a linguagem Java suporta vários recursos de alto desempenho, como multithreading4, compilação just-in-time5 e utilização de código nativo. O byte-code do Java possui um desempenho aproximadamente 20 vezes inferior que o de um código nativo do processador (ou linguagem de máquina), mas que em comparação com linguagens Script, como o HTML6, o JavaScript ou o VBScript, ou até mesmo o próprio byte-code do Visual Basic, possui uma performance muitas vezes superior. Esta performance, pela quantidade de esforços aplicados sobre a sua otimização pelos desenvolvedores de Java, está cada vez mais sendo aumentada, podendo um dia comparar-se com uma linguagem compilada para o processador em específico (linguagem nativa). Inclusive já foram criados processadores para suportar diretamente o byte-code da linguagem Java. 4 Com multithreading (figura 1) podemos fazer nossos programas executarem diferentes partes do código ao mesmo tempo. Isso pode ser muito útil, por exemplo, se desejamos deixar parte do programa realizando um cálculo de contabilidade complexo para emissão de um relatório, enquanto o usuário continua utilizando outras partes do programa, sem interrupção. Figura 1: Esquema de multithreading. Fonte: http://www.microsoft.com/brasil/msdn/Tecnologias/vbnet/Multithreading.mspx. 5 A medida que cada método dentro do executável é chamado, ele é compilado para o código nativo; chamadas subseqüentes para o mesmo método não tem o peso da mesma compilação, então o overhead é pago apenas uma vez. 6 HTML – HyperText Markup Language (Linguagem de Marcação de Hipertexto), é uma das linguagens utilizadas para desenvolver páginas na internet, existem outras linguagens mais avançadas porém dificilmente você verá um site que não utilize HTML. Apostila de Java Página 3 de 25 Prof. Danton Cavalcanti Franco Junior – [email protected] – http://www.dantonjr.com.br Garbage Collection (Libera uma coleção): O Java não segura áreas de memória que não estão sendo utilizadas, isto porque ele tem uma alocação dinâmica de memória em tempo de execução. No C e C++ (e em outras linguagens) o programa desenvolvido é responsável pela alocação e desalocação da memória. Durante o ciclo de execução do programa o Java verifica se as variáveis de memória estão sendo utilizadas, caso não estejam o Java libera automaticamente esta área que não esta sendo utilizada. Incorporação com Bando de Dados: a linguagem Java está agora incorporando suporte a operações em Banco de Dados. O JDBC7, que é uma biblioteca de classes para acesso a banco de dados, permite uma conexão remota a servidores SQL 8 que possuam driver OBDC9 ou compatível. Transações no estilo de Compras, Vendas, Cadastramentos, Alteração de dados pessoais controlada por senha via Internet, são exemplos do que o JDBC permite que seja realizado. 2. Desenvolvimento Java Basicamente o Java apresenta três formas distintas de desenvolvimento de aplicativos: Aplicação, Applet e Servlet. 2.1. Aplicação Aplicação é um programa mais geral escrito na linguagem Java. Não requer um browser nem estruturas de servidor, etc., para sua execução. De fato, Java pode ser usada para criar todo tipo de aplicações que usualmente você implementa com outras linguagens mais convencionais. Como exemplo, podemos ter o desenvolvimento de uma aplicação normal, que roda na própria máquina do usuário (figura 2). Figura 2: Aplicação, classe e processamento na própria máquina do usuário. Os exemplos para aplicações serão discutidos mais a frente, em momento oportuno. 2.2. Applet Applet é um programa especial escrito em Java adaptado para instalação e execução dentro de páginas HTML. Estas páginas podem então ser visualizadas num browser. Um applet possui vários recursos gráficos para a apresentação de dados na tela, sendo que os recursos mais comuns de apresentação de dados, as saídas padrões do Java, não funcionam no browser, pois são recursos não gráficos. Um applet possui várias implementações de segurança que um aplicativo Java não tem. Enquanto que em um aplicativo normal em Java você pode, por exemplo, ler, gravar, alterar arquivos e configurações do sistema, a linguagem Java impede que um applet faça qualquer tipo de acesso a recursos físicos do sistema que está sendo utilizado. Mas há exceções: isto depende da versão do Java que está sendo utilizada, e versões mais antigas possuem menos recursos de proteção ao sistema. O Código do applet fica no servidor, no momento do acesso, a máquina virtual Java é executada pelo browser, na seqüência recebe do servidor a classe e é então executado dentro desta estrutura (figura3). O processamento ocorre na máquina do usuário. 7 JDBC – Java DataBase Connection. Um driver JDBC é o método de acesso que permite aplicações desenvolvidas em linguagem Java acessar diferentes fontes de dados. 8 SQL – Structured Query Language. É a notação padrão para linguagens de instruções enviadas a um banco de dados. Deve ser utilizada em conjunto com um banco de dados relacional. 9 ODBC – Open Database Connectivity. Um driver ODBC é o método de acesso que permite aplicações desenvolvidas em diversas linguagens acessar diferentes fontes de dados. Apostila de Java Página 4 de 25 Prof. Danton Cavalcanti Franco Junior – [email protected] – http://www.dantonjr.com.br Figura 3: Applet, o servidor envia a classe para a máquina do cliente que faz o processamento. Abaixo podemos ver um exemplo de um applet (quadro 1). Código Resultado Applet import java.applet.Applet; import java.awt.*; public class MeuApplet extends Applet { private Font FonteTitulo, FonteTexto; public void paint(Graphics g) { FonteTitulo = new Font("Verdana", Font.BOLD, 20); FonteTexto = new Font("Times", Font.ITALIC, 14); g.setColor(Color.blue); g.setFont(FonteTitulo); g.drawString("Título", 10, 20); g.setFont(FonteTexto); g.setColor(Color.black); g.drawString("Meu Texto - Linha 1", 10, 40); g.drawString("Meu Texto - Linha 2", 10, 60); g.setColor(Color.yellow); g.fillOval(10,80,150,80); g.setColor(Color.cyan); g.fillArc(10,160,40,40,0,290); g.setColor(Color.red); g.fillRect(50, 160, 40, 40); } } HTML <HTML> <HEAD> <TITLE> Página de um Applet </TITLE> </HEAD> <BODY> Texto da página:<br> Pode conter: <b>linhas, tabelas, imagens, etc...</b><p> <APPLET CODE="MeuApplet.class" WIDTH=300 HEIGHT=450> </APPLET> </BODY> </HTML> Quadro 1: Exemplo de um Applet. Note o processamento todo no browser. A seguir, a lista de parâmetros da tag <applet> que podem ser usados na apresentação das applets e para que servem (o exemplo na seqüência mostra o uso dessa tag): <applet code=<arquivo> nome do arquivo da classe a ser executada (sem path) width=<pixels> largura do espaço que o applet pode ocupar no browser heigth=<pixels> altura do espaço que o applet pode ocupar no browser [codebase=<URL>] URL onde se encontra as classes a serem executadas [vspace=<pixels>] espaço vertical deixado em branco ao redor do applet [hspace=<pixels>] espaço horizontal em branco ao redor do applet [align=<sentido>] alinhamento na página (left, right, top, middle, ...) Apostila de Java Página 5 de 25 Prof. Danton Cavalcanti Franco Junior – [email protected] – http://www.dantonjr.com.br [alt=<texto>] texto a ser exibido se o browser não suporta applets [name=<nome>] nome da applet para que outras applets executadas na mesma página possam se comunicar com ela > A página HTML pode passar parâmetros para o applet, com a tag <PARAM> o que é descrito e ilustrado logo a seguir: <param name=nome_parâmetro value=valor_parâmetro> como em: <PARAM NAME="Nome" VALUE="Danton Cavalcanti Franco Junior"> Pode-se trabalhar com um número desconhecido de parâmetros usando para isso um mesmo nome com uma numeração seqüencial, como a seguir: <PARAM NAME="param1" VALUE="Danton Cavalcanti Franco Junior"> <PARAM NAME="param2" VALUE="Programação 2"> <PARAM NAME="param3" VALUE="Curso de Java"> e recuperá-los em um laço de iteração como: proximo = getParameter("param" + i ); i+; Antes de encerrar a tag <applet> pode ser inserido o código que será apresentado nas situações em que o browser não reconhecer a tag. Cabe observar que apesar do HTML ignorar a distinção entre maiúsculas e minúsculas deve-se considerá-la quando se está passando valores para os parâmetros da tag e/ou para a classe. O código do applet não apresenta o procedimento main() e é executado no browser como “um objeto de linha de execução” (thread), portanto, capaz de executar ações de janela (painel) e de linha de execução. O método paint é o responsável por desenhar a parte gráfica do applet na tela e apresenta o sistema de coordenadas cujo canto superior esquerdo é (0,0). Ele é chamado automaticamente pelo browser. 2.3. Servlet Servlet é um programa que estende a funcionalidade de um web server, gerando conteúdo dinâmico e interagindo com os clientes utilizando o modelo request/response. Veja a figura 4. Os servlets não são restritos ao modelo HTTP10 de request/response, mas esse é o modelo mais comumente utilizado. Todos os servlets implementam direta ou indiretamente a interface Servlet. O mais comum é o servlet dar extends na HttpServlet (que implementa a interface Servlet). A interface Servlet fornece métodos para gerenciamento do servlet e sua comunicação com clientes. Quando um servlet aceita uma chamada do cliente, ele recebe dois objetos: ServletRequest e ServletResponse. A classe ServletRequest encapsula a comunicação do cliente com o servidor, enquanto a ServletResponse encapsula a comunicação do servidor com o cliente. A ServletRequest permite que o servlet acesse informações como os nomes dos parâmetros passados pelo cliente, o protocolo usado pelo mesmo e o nome do host que fez o chamado ao servidor. Ela também permite que o servlet acesse um inputstream – o ServletInputStream – através do qual o servlet recebe dados do cliente. As subclasses da ServletRequest permitem ao servlet obter dados mais específicos, como informações do cabeçalho HTTP. A ServletResponse fornece ao servlet métodos para responder ao cliente. Ela permite que o servlet defina o tamanho do conteúdo e seu mime type, fornece uma OutputStream – a ServletOutputStream – e também um Writer, através dos quais o servlet poderá enviar respostas ao cliente. As subclasses da ServletResponse fornecem ao servlet mais capacidades específicas em relação ao protocolo, como manipular o cabeçalho HTTP da resposta. 10 HTTP – HyperText Transfer Protocol (Protocolo de Transferência de Hipertexto), o HTTP é o protocolo usado para a transmissão de dados no sistema World-Wide Web (www). Cada vez que você aciona um link, seu browser realiza uma comunicação com um servidor da Web através deste protocolo. Apostila de Java Página 6 de 25 Prof. Danton Cavalcanti Franco Junior – [email protected] – http://www.dantonjr.com.br Figura 4: Servlet, o servidor recebe a requisição, processa e envia os resultados. Abaixo podemos ver um exemplo de um servlet (quadro 2). Código Resultado HTML <HTML> <HEAD> <TITLE> Somador Simples </TITLE> </HEAD> <BODY> <form action="../meusservlets/servlet/Calcula" method="POST" name="Calcula"> <p> <b><center>Calculando a soma de 2 números</center></b> <p> Nro1:<br> <input type="text" size="20" name="Nro1"> <p> Nro2:<br> <input type="text" size="20" name="Nro2"> <p> Digite seu nome: <input type="text" size="50" name="Nome"> <p> <input type="submit" name="Benvia" value="Enviar"> <input type="reset" name="Breseta" value="Redefinir"> </form> </BODY> </HTML> Apostila de Java Página 7 de 25 Prof. Danton Cavalcanti Franco Junior – [email protected] – http://www.dantonjr.com.br Servlet import java.io.*; import java.text.*; import javax.servlet.*; import javax.servlet.http.*; public class Calcula extends HttpServlet { public void doPost(HttpServletRequest pergunta, HttpServletResponse resposta) throws IOException, ServletException { resposta.setContentType("text/html"); PrintWriter out = resposta.getWriter(); out.println("<HTML>"); out.println("<HEAD>"); out.println("<TITLE>" + "Resultado da Soma" + "</TITLE>"); out.println("</HEAD>"); out.println("<BODY>"); String Num1 = pergunta.getParameter("Nro1"), Num2 = pergunta.getParameter("Nro2"), Nome = pergunta.getParameter("Nome"); out.println("<P>" + Nome + ",</P>"); int Resultado = Integer.parseInt(Num1) + Integer.parseInt(Num2); out.println("<P> A soma de " + Num1 + " com " + Num2 + " é <b>"+ Resultado +"</b>.<BR>"); out.println("</BODY>"); out.println("</HTML>"); out.close(); } } Quadro 2: Exemplo de um servlet. Repare a requisição e o resultado do servidor. 3. Instalação e Configuração do Java Passos para instalar e configurar o Java. 3.1. Instalação Deve-se primeiramente baixar o Java a partir do site da Sun http://java.sun.com. Recomenda-se o J2SE 1.4.2 SDK, ou o J2SE 5.0. No mesmo site, também é possível baixar a documentação do Java, com referências aos comandos e classes da linguagem. Quando da instalação do J2SE 5.0, os arquivos são copiados em uma pasta, como por exemplo a pasta: “C:\Arquivos de programas\Java\jdk1.5.0_05”. Vale lembrar que todos os arquivos de compilação, e execução, estão dentro da subpasta “bin”. 3.2. Configuração Após a instalação do Java, devemos nos preocupar basicamente com a configuração de duas variáveis: CLASSPATH e PATH. 3.2.1. Variável CLASSPATH Durante a configuração do Java, deve ser criada uma variável de ambiente com o nome de CLASSPATH, que deve conter o seguinte conteúdo: <drive>:\<diretório do Java>\lib Recomenda-se verificar o conteúdo dessa variável, para preservar o valor anterior adicionando o novo caminho, deve-se usar o seguinte comando (preferencialmente respeitando as maiúsculas): Set CLASSPATH=%CLASSPATH%;C:\Arquivos de programas\Java\jdk1.5.0_05\lib;. Variável Conteúdo anterior Caminho do Java o . (ponto) representa o diretório atual. É possível, colocar classes em arquivos, zip, dessa forma, deve-se colocar o nome do arquivo juntamente no caminho da variável CLASSPATH. Isto faz com que o Java, quando estiver precisando de alguma classe que esteja dentro de algum pacote, procure a classe desejada dentro deste arquivo (arquivo zipado). Se a encontrar, o Java descompacta a classe e a utiliza. Este método de compactar os pacotes com as suas classes correspondentes faz, com que se economize espaço em disco. Apostila de Java Página 8 de 25 Prof. Danton Cavalcanti Franco Junior – [email protected] – http://www.dantonjr.com.br 3.2.2. Variável PATH Essa variável é responsável por indicar o caminho dos arquivos onde o Sistema Operacional deve buscar os arquivos executáveis. Como dito anteriormente, esses arquivos (no Java), encontram-se dentro da pasta Bin. O comando para fazer a inclusão desse caminho seria: Set PATH=%PATH%;C:\Arquivos de programas\Java\jdk1.5.0_05\bin 3.2.3. Verificação das Variáveis É possível verificar o conteúdo das variáveis digitando-se na janela de prompt, o comando SET, obtendo-se como resultado, algo parecido com o descrito abaixo (vale lembrar que os valores mostrados abaixo, podem variar de computador para computador, dependendo da configuração de cada um – repare nas variáveis PATH e CLASSPATH): ALLUSERSPROFILE=C:\Documents and Settings\All Users APPDATA=C:\Documents and Settings\Danton Junior\Dados de aplicativos BUFFERS=8 CLASSPATH=C:\Arquivos de programas\Borland\InterBase\InterClient\interclient.jar;C:\Arquivos de programas\Java\jdk1.5.0_05\lib;C:\Arquivos de programas\Java\jdk1.5.0_05\src.zip;. CLIPPER=255 CommonProgramFiles=C:\Arquivos de programas\Arquivos comuns COMPUTERNAME=PRINCIPAL ComSpec=C:\WINDOWS\system32\cmd.exe FILES=255 FP_NO_HOST_CHECK=NO HOMEDRIVE=C: HOMEPATH=\Documents and Settings\Danton Junior LOGONSERVER=\\PRINCIPAL NUMBER_OF_PROCESSORS=2 OS=Windows_NT Path=C:\Arquivos de programas\Corel\Corel SVG Viewer\;c:\arquivos de programas\Inprise\vbroker\bin;C:\Arquivos de programas\Borland\Delphi7\Bin;C:\Arquivos de programas\Borland\Delphi7\Projects\Bpl\;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;" C:\Arquivos de programas\Norton SystemWorks\Norton Ghost\";C:\Arquivos de programas\IDM Computer Solutions\UltraEdit-32;C:\Arquivos de programas\WGet;C:\Arquivos de programas\Java\jdk1.5.0_05\bin;C:\Arquivos de programas\Java\Sun\AppServer\bin PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH PROCESSOR_ARCHITECTURE=x86 PROCESSOR_IDENTIFIER=x86 Family 15 Model 4 Stepping 1, GenuineIntel PROCESSOR_LEVEL=15 PROCESSOR_REVISION=0401 ProgramFiles=C:\Arquivos de programas PROMPT=$P$G SESSIONNAME=Console SystemDrive=C: SystemRoot=C:\WINDOWS TEMP=C:\DOCUME~1\DANTON~1\CONFIG~1\Temp TMP=C:\DOCUME~1\DANTON~1\CONFIG~1\Temp USERDOMAIN=PRINCIPAL USERNAME=Danton Junior USERPROFILE=C:\Documents and Settings\Danton Junior VBROKERDIR=c:\arquivos de programas\Inprise\vbroker windir=C:\WINDOWS 3.3. Compilando e Executando Vamos tomar como exemplo a hipótese de se ter um programa (arquivo) de nome: “programa.java”. Nos exemplos o cifrão ($) representará para nós o prompt do Sistema Operacional. 3.3.1. Compilando Para compilar, usamos o comando: javac: $ javac programa.java Este comando submete o programa “programa.java” a compilação e gera o byte-code respectivo com o nome de “programa.class”. No caso de aplicativos, para executar (após compilado) o programa invoca-se o interpretador Java com a sintaxe a seguir: $ java programa Apostila de Java Página 9 de 25 Prof. Danton Cavalcanti Franco Junior – [email protected] – http://www.dantonjr.com.br Este comando executa o byte-code do aplicativo. Para inspecionar o código gerado pelo compilador (byte-code) utiliza-se: $ javap –c programa No caso de applets, para visualizá-los invoca-se o appletviewer que apresentará o applet no ambiente gráfico, como a seguir: $ appletviewer meuapplet.html Nota-se que é chamada a página HTML que contém a referência ao applet e não a classe diretamente. Para gerar a documentação em HTML tendo como origem o programa fonte utiliza-se o javadoc, como descrito abaixo: $ javadoc programa.java Nota-se que é chamado fonte e não a classe, uma vez que os comentários estão no primeiro arquivo. 4. O Básico Este capítulo descreve os comandos básicos do Java, e seu funcionamento. 4.1. Variáveis Variáveis são alocações de memória nas quais podemos guardar dados. Elas têm um nome, tipo e valor. Toda vez que necessite usar de uma variável você precisa declará-la e só então poderá atribuir valores a mesma. 4.1.1. Declarando variáveis As declarações de variáveis consistem de um tipo e um nome de variável, como segue o exemplo: int Ano; int Mês = 12; String Nome; boolean Ativo; Os nomes de variáveis podem começar com uma letra, um sublinhado (_), ou um cifrão ($). Elas não podem começar com um número. Depois do primeiro caractere pode-se colocar qualquer letra ou número. 4.1.2. Tipos de Dados No Java existem oitos tipos básicos e um tipo especial. 4.1.2.1. Tipo Lógico Aceita os valores true e false. 4.1.2.2. Tipo Textual O tipo char, aceita apenas um caractere. O tipo char representa na forma Unicode11 um caractere de 16-bit (2 bytes). O literal do tipo char pode ser representado com o uso do apóstrofo (‘ ‘). Alguns exemplos de caracteres especiais: Representação visual: \n \r \b \t \f \’ \” \\ \u223d \gfa \fff 11 Função, significado: Pula linha, linefeed Retorno de carro Backspace Tabulação Formfeed Apóstrofo Aspas Barra inversa Caractere Unicode de número 223 Octal Hexadecimal O Unicode fornece um único número para cada caractere, não importa a plataforma, não importa o programa, não importa a língua. Apostila de Java Página 10 de 25 Prof. Danton Cavalcanti Franco Junior – [email protected] – http://www.dantonjr.com.br Há também a classe String, que discutiremos posteriormente. 4.1.2.3. Tipos Inteiros Os tipos inteiros são divididos em: byte, short, int e long, conforme a mostrado abaixo: Tipo Tamanho Alcance byte 8 bits -128 a 127 -27..27 - 1 short 16 bits -32.768 a 32.767 -215..215 - 1 int 32 bits -2.147.483.648 a 2.147.483.647 -231..231 - 1 long 64 bits -9.223.372.036.854.775.808 até 9.223.372.036.854.775.807 -263..263 - 1 Não existem especificadores de tipos como unsigned, todos os tipos “inteiros” têm sinal. Valores literais: O que você vê nem sempre é o que você tem: Um valor como 299.792.458 é considerado int como padrão, se você quer atribuir esta constante a um long, faça o type cast explicitamente: long a; a=(long)299792458; Ou então use uma terminação em L para indicar que o número deve ser representado como long: long a=299792458L; //ou L minúculo. Para indicar valores octais anteceda-os com um zero: 0444, já para valores hexadecimais antecedaos com 0X ou 0x, exemplo: 0xBCD4. 4.1.2.4. Tipos Reais Os tipos reais são divididos em: float e double, conforme abaixo: Tipo Norma float Ponto flutuante 32-bit IEEE754 double Ponto flutuante 64-bit IEEE754 Tamanho Precisão 4 bytes 6-7 dígitos significativos 8 bytes 15 dígitos significativos Um valor como 3.14159265 é considerado double como padrão, se você deseja atribuir esta constante a um float, faça o type cast explicitamente: float a; a=(float)3.14159265; Ou então usar uma terminação em F para indicar que o número deve ser representado como float: float a=3.14159265f; //ou F minúsculo. Expoentes podem ser escritos usando o caractere “e” ou “E”, por exemplo: 6,02E23 ou 1.380658e23. Onde e-1, significa multiplicado por dez elevado a menos 1 ou *0.1 – O separador de casas decimais é o ponto. Apesar de todas estas regras para uso de valores literais, quando dois números de tipo diferentes como double e int são usados em um cálculo do lado direito de uma atribuição, você não precisa fazer o type cast desses valores. O compilador promove o número do tipo mais fraco para o tipo mais forte antes de fazer o cálculo. Você pode desejar fazer o type cast do resultado, para atribuir a uma variável long, por exemplo. 4.1.2.5. Tipos String O tipo String é uma seqüência de caracteres. Java não possui um tipo de string interno. Em vez disso, a uma biblioteca padrão que contém uma classe predefinida chamada String. Por exemplo: String e = ""; // uma string vazia String Saudação = "Bem-vindo"; Java permite usar o sinal de adição (+) para concatenar duas strings: String V1 = "Boa"; String V2 = "Noite"; String Mensagem = V1 + " " + V2; // Retorna Boa Noite Também é possível concatenar uma string com uma não string. int Total = 50; System.out.println("Total: " + Total); // Retorna Total: 50 Por ser uma classe, o tipo String dispõe de métodos para a manipulação de seus valores. São exemplos: Para extrair uma substring de uma string, utilize a variável seguida do método substring: V1.substring(0,4); // Retorna "Boa " Para descobrir o tamanho de uma string, utiliza o método length: V1.length(); // Retorna 9 Apostila de Java Página 11 de 25 Prof. Danton Cavalcanti Franco Junior – [email protected] – http://www.dantonjr.com.br Para testar a igualdade de duas strings, utilize o método equals: V1.equals(V2); // Retorna true se a string V1 for igual a V2 Para saber um caractere em específico da string, utiliza-se o método chatAt: Mensagem.charAt(4); // Retorna ‘N’ Para converter em maiúsculas, usa-se o método toUpperCase: Mensagem.toUpperCase(); // Retornaria “BOA NOITE” 4.1.4. Palavras Reservadas Palavras reservadas significado especial par ao palavras reservadas: abstract boolean breaak byte case catch char class continue default são elementos de linguagem que foram reservados pelo Java e tem um compilador, portanto não podem ser usadas como nome de variáveis. São do double else extends false final finally float for if implements import instanceof int interface long native new null package private protected public return short static super switch synchronized this Throw Throws Transient True Try Void Volatile While 4.2. Constantes Java tem problemas para lidar com constantes. Não é possível declarar constantes locais para um método individual como main. Em vez disso, só pode ter constantes disponíveis para todos os métodos na classe, por exemplo: public class ExemploTipos { static final double MinhaConstante = 32; // Declaracao de uma constante public static void main(String[] args) { System.out.println("Constante: " + MinhaConstante); } } 4.3. Comentários Os comentários podem ser de três formas: Utilizando //, dessa forma, comentamos apenas uma linha; Para mais de uma linha, utilizamos /* para iniciar, e */ para finalizar. A outra forma é utilizada para identificar o texto a ser incluído na geração automática da documentação. Para isso usamos a seqüência /** texto do documento */. 4.4. Ponto e Vírgula, Blocos e o Espaço em Branco Utilizam-se as seguintes convenções em Java: Os comandos são terminados com o sinal de ponto e vírgula “;”. Um bloco tem início e seu fim representado pelo uso das chaves: “{“ – início e “}” – fim. O uso do espaço em branco permite uma melhor visualização dos comandos e em conseqüência facilita a sua manutenção. Letras maiúsculas e minúsculas são diferentes entre si. Nomes de classes (class) podem ser maiúsculos ou minúsculos, ou misturado (maiúsculas e minúsculas), mas por convenção o nome das classes começa por letra maiúsculas. Apostila de Java Página 12 de 25 Prof. Danton Cavalcanti Franco Junior – [email protected] – http://www.dantonjr.com.br 4.5. Expressões e Operadores Operadores aritméticos podem ser usados na inicialização das variáveis ou em outros momentos. Os mais comuns são (+ - * /), adição, subtração, multiplicação e divisão, respectivamente. O operador / indica divisão inteira se os dois argumentos forem inteiros, e divisão em ponto flutuante caso contrário. O resto de divisão é representado por %. Não há um operador para a exponenciação, é necessário utilizar um método da classe match (possui várias funções matemáticas), denominado pow. 4.5.1. Operadores Aritméticos Usados para cálculos matemáticos, são eles: Operador Significado + soma subtração * multiplicação / divisão % módulo Exemplo 3+4 5-7 5*5 14 / 7 20 % 7 4.5.2. Operadores Relacionais Java possui várias expressões para testar igualdade e magnitude. Todas as expressões retornam um valor booleano (true ou false). Os operadores relacionais são: Operador Significado == igualdade != desigualdade >= maior igual <= menor igual > maior que < menor que && e condicional || ou condicional 4.5.3. Outros Operadores Completam a lista de operadores disponíveis: Operador Significado ~ Move os bits de um inteiro ! Não lógico (reverte um booleano) << >> Deslocamento de bits para direita ou esquerda & and bit a bit | or bit a bit ^ ou exclusivo (xor) negação 4.5.4. Expressões Existem expressões com prefixo e sufixo: Quando se usa o sufixo, como os operadores (x++ ou x--), y recebe o valor de x antes de x ser incrementado. Usando o prefixo (++x ou –x) acontece o contrário, y recebe o valor incrementado de x. Como: y = x++; y = --x; Também são válidos o uso de expressões na inicialização de variáveis: int x, y, z; x = y = z = 0; Apostila de Java Página 13 de 25 Prof. Danton Cavalcanti Franco Junior – [email protected] – http://www.dantonjr.com.br ou também: Expressão Significado x += y x=x+y x -= y x=x-y x *= y x=x*y x /= y x=x/y O Java aceita expressões do tipo: int i, j, k; i=0; j=k=i + 3; // No final, j vale 3, k vale 3 e i continua valendo 0 Essas atribuições em cadeia permitem escrever código mais compacto, elas fazem sentido porque atribuições nessas linguagens possuem valores, assim k=i+3; no final tem o valor de k que é igual a i+3. As expressões matemáticas podem ser usadas normalmente como em outra linguagem qualquer. 4.6. A Estrutura de um Programa Java A estrutura básica de uma classe pode ser definida por: public class PrimeiroEx { public static void main(String[] args) { System.out.println("Meu Primeiro Programa!"); } } O interpretador Java sempre iniciará a execução com o código no método main da classe nomeada. Assim é necessário um método (função) main para que o código seja executado. Cada aplicativo deve ter um método cujo cabeçalho seja idêntico ao apresentado acima. O nome do arquivo deverá ser igual ao nome da classe, pois a mesma foi definida como public. 4.7. Estruturas de Controle Em Java estão disponíveis estruturas de controle comuns a outras linguagens de programação. Estas construções podem ser agrupadas como sendo de seleção, iteração e transferência de controle. 4.7.1. Seleção Permitem o desvio na execução do programa. 4.7.1.1. If/Else Permite desvio da execução normal do programa mediante escolha entre duas alternativas. if ( Expressão ) Instrução [ else Instrução ] if (expressão) // Expressão cujo retorno é um valor do tipo boolean { Declarações ou blocos } else // Caso a condição anterior não seja satisfeita { Declarações ou blocos } Onde Expressão é do tipo boolean e Instrução é qualquer instrução ou um bloco { }. A Instrução após cláusula else, quando existir, será executada se a Expressão for falsa. Pode-se usar operador “?”, como abaixo: System.out.println(“O número é “ + ((n%2) == 0 ? ”par” : ”ímpar”)); Apostila de Java Página 14 de 25 Prof. Danton Cavalcanti Franco Junior – [email protected] – http://www.dantonjr.com.br 4.7.1.2. Switch Permite o desvio da execução mediante escolha de diversas alternativas. switch (Expressão) // Expressão deve ser do tipo int ou char { case constante_1 : Instrução; // Ou conjunto de instruções. break ; case constante_2 : Instrução; // Ou conjunto de instruções. break ; case constante_3 : Instrução; // Ou conjunto de instruções. break ; [default: Instrução; break ;] } Onde Expressão é uma expressão do mesmo tipo das constantes. A instrução break finaliza a execução da Instrução (ou conjunto de instruções) e se omitida permitirá que as Instruções seguintes executem (não recomendado). A Instrução após a cláusula default, quando esta estiver presente, será executada se a Expressão não coincidir com nenhuma das constantes anteriormente declaradas. 4.7.2. Iteração As instruções desse tipo, permitem a repetição da execução de trechos de código através de condições de controle. 4.7.2.1. For O comando for é controlado por incremento. Permite a declaração da variável de controle na própria instrução e mais de uma variável de na cláusula. for ( i=0; i<100; i++) { Comandos; } ou for ( ; ; ) // Laço infinito { Comandos; } ou for (int i=0; i<100; i++) { Comandos; } ou for (i=0, j=0; i<100; i++, j+=2) { Comandos; } 4.7.2.2. While O comando while é controlado por uma expressão booleana, executando as instruções do laço enquanto a condição permanecer verdadeira. while ( Expressão ) Instrução ; while(condição_boolean) { Declarações ou blocos de comandos; } Executa zero ou mais vezes a Instrução ou bloco {}. Pois a condição booleana pode ser falsa já na entrada do laço. Apostila de Java Página 15 de 25 Prof. Danton Cavalcanti Franco Junior – [email protected] – http://www.dantonjr.com.br 4.7.2.3. Do While O comando do while, é controlado por uma expressão booleana, executando as instruções do laço enquanto a condição permanece verdadeira. do Instrução while ( Expressão ) ; do { Declarações ou blocos de comandos; } while(condição_boolean); Como o teste lógico é feito no final do laço, os comandos declarados no bloco {} são executados pelo menos uma vez. 4.7.2.4. Continue O comando continue é usado com os laços de repetição e desvia a execução para o início do laço. 4.7.2.5 Break O comando break é usado com os laços de repetição e desvia a execução para a instrução após o final do laço. 4.7.3. Transferência de controle Permite o desvio da execução entre módulos diferentes. Usa-se o comando return. Desta forma permite-se o desvio na execução entre diferentes módulos de programas retornando ao ponto onde o módulo foi chamado, devolvendo um valor ou não. return; ou return Expressão ; Onde Expressão é uma expressão do mesmo tipo do método onde a return foi declarada (não permitido para métodos void, pois métodos desse tipo não retornam nada). Sem a Expressão simplesmente encerra a execução do módulo retornando para quem o chamou. 4.8. Vetores (Arrays) Um array em Java possui além dos seus elementos, informações extras como o seu tamanho. Vale lembrar que um array é uma classe, portanto possui métodos para sua manipulação. Uma vez declarado, um array não pode ter seu tamanho alterado, a menos que você possa substituí-lo atribuindo a ele um objeto de array de tamanho diferente. Cabe notar que o primeiro elemento do array é o de índice 0. Portanto, uma variável array com 300 elementos terá índices que variam de 0 à 299. Uma referência a um elemento inexistente no array causará uma exceção. Os arrays em Java são diferentes do que em outras linguagens. Arrays em Java são objetos que podem ser passados e acoplados a outros objetos, podem conter qualquer tipo de elemento valorado (tipos primitivos ou objetos), mas você não pode armazenar diferente tipos em um simples array. Ou seja, você pode ter um array de inteiros, ou um array de strings, ou um array de array, mas você não pode ter um array que contenha ambos os objetos strings e inteiros. A restrição acima descrita significa que os arrays implementados em Java são genéricos homogêneos, ou seja, um único array pode armazenar qualquer tipo de objeto com a restrição que todos sejam da mesma classe. A declaração de uma variável array, bem como sua instanciação, pode ser feita como a seguir: int alunos[] = new int[300]; // Array de 300 elementos inicializado com 0; int idades[] = {15, 19, 23, 29}; // Array já inicializado Quando você cria um objeto array usando o operador new, todos os índices são inicializados para você (com 0 para arrays numéricos, falso para boolean, ‘\0’ para caracteres, e NULL para objetos). Entretanto também é possível criar e inicializar um array ao mesmo tempo. Pode-se criar arrays com mais de uma dimensão, que em Java denominam-se arrays de arrays. Para declarar-se um array de array usa-se a seguinte sintaxe: String Nomes[][]; Apostila de Java Página 16 de 25 Prof. Danton Cavalcanti Franco Junior – [email protected] – http://www.dantonjr.com.br Para instanciar um array deste tipo pode-se utilizar uma construção como a apresentada a seguir: Strings Turmas[][]; String TurmaA [] = {“Junior“, “Paula“, “Simone“}; String TurmaB [] = {“Daniel“, “Danúbia“, “Dalton“}; Turmas[0] = TurmaA; Turmas[1] = TurmasB; ou, então, String Turmas[][] = new String[2][]; for (int i=0; i<Turmas.lenght; i++) { String Temp[] = new String[]; for (int j=0; j<Turmas.lenght; j++) Temp[j] = “Sem Nome“ + j; Turmas[i] = Temp; } ou, ainda, String Turmas[][] = {{“Junior“, “Paula“, “Simone“} {“Daniel“, “Danúbia“, “Dalton“} }; Quando instancia-se as dimensões em momentos diferentes deve-se instanciar as mais significativas primeiro: String Nomes[][] = new String [5][] ; // Correto String Nomes[][] = new String [5][3] ; // Correto String Nomes[][] = new String [][3] ; // ERRADO A declaração de um método que retorna arrays pode ser feita conforme a sintaxe: int [] notas { return new int[3] ; } Para se acessar os elementos do array, utiliza-se o índice do mesmo: Idades[2] = 28; O tamanho de um array é um campo na classe array e não um método, portanto é recuperado como a seguir: idades.length; // Retorna o número de elementos no array Para obter o tamanho de um array de Strings e o tamanho de uma determinada String deste array, pode-se basear no código a seguir (o qual tem um uso muito freqüente): public static void main (String args[]) { int i = 0; System.out.println(“Número de strings: “ + args.length); System.out.println(“Tamanho da i_esima String: “ + args[i].length()); } ; 4.9. Instruções de Guarda – Tratamento de Exceções Para situações excepcionais, como dados de entrada inválidos com potencial para arruinar a execução de um programa, Java usa uma forma de captura de erros chamada de manipulação de exceções (exception-handling). Em Java, a classe de Exceção define condições de erro moderados que seus programas podem encontrar. Em vez de você deixar o programa terminar, você pode escrever um código para tratar as exceções e continuar a execução do programa. Um erro pode ser causado por um arquivo contendo informações erradas, uma conexão de rede partida ou um acesso a um elemento inexistente de um array ou referência nula no código. Os usuários esperam que os programas sejam sensíveis em condições de erro. Se uma operação não puder ser completada por causa de um erro, o programa deve: Retornar para um estado seguro e permitir que o usuário execute outros comandos. Salvar todo o trabalho e concluir o programa tranqüilamente. Esta é uma tarefa nem sempre fácil. O código que detecta (ou ainda causa) a condição de erro geralmente fica bem separado do código que pode retornar os dados a um estado seguro, ou salvar o trabalho do usuário. A missão central da manipulação de exceções é transferir o controle de onde ocorreu o erro para um manipulador de erro que possa lidar com a situação. Exceções servem para alterar o fluxo de controle quando um evento importante ou inesperado, normalmente um erro, ocorre. Apostila de Java Página 17 de 25 Prof. Danton Cavalcanti Franco Junior – [email protected] – http://www.dantonjr.com.br Uma RuntimeException ocorre devido a algo ruim, como um erro de I/O que aconteceu ao programa. Exceções herdadas de RuntimeException incluem problemas como: uma conversão de tipos errada; um acesso de array fora dos limites; um acesso com ponteiro nulo. As exceções que não são herdadas de RuntimeException incluem: tentativa de ler além do final de um arquivo; tentativa de abrir uma URL mal formada; tentativa de encontrar um objeto class para uma string que indica uma classe não existente. A forma geral para capturar uma exceção é usando a instrução try. A instrução try testa todas as instruções e verifica se encontra uma exceção. A instrução try deve ser seguida por, pelo menos, uma cláusula catch ou por uma cláusula finally. Cada catch manipula qualquer exceção que corresponda a um argumento. Corresponder a um argumento significa que a exceção lançada pôde ser atribuída legalmente à exceção do argumento. É possível capturar várias exceções sucessivas através da cláusula catch, cada uma diferente da outra. O bloco finally, se presente, é uma “última chance de limpeza”. O bloco finally é executado se a exceção ocorreu ou não. Ele é executado depois dos blocos catch, se existirem, e se um deles capturou uma exceção ou não. Abaixo podemos observar a estrutura do comando try: try { // Bloco de código } catch (TipoExceção e1) { // Manipulador para este tipo. // É preciso pelo menos uma instrução catch. } catch (TipoExceção e2) { // Outro Manipulador } finally { // Finalizador. É Opcional. } Se qualquer parte do código dentro do bloco try passar uma exceção da classe indicada na cláusula catch, então: 1. Java pula o restante do código do bloco try; 2. Executa o código do manipulador dentro da cláusula catch. Se nenhum código dentro do bloco try passar uma exceção, então Java pula a cláusula catch. Se qualquer parte de um método passar uma exceção de um tipo diferente daquele nomeado na cláusula catch, Java deixa o método imediatamente. Também é possível silenciar uma exceção, ou seja, ignorar a exceção e continuar a execução do programa. Exemplo: Try { // Bloco de instruções } catch (IOException e) {} O trecho acima informa para “não terminar o programa se houver um erro, apenas ignorar o erro e não executar o restante bloco de instruções”. Isto é possível não informando nenhuma instrução para a opção catch. Apostila de Java Página 18 de 25 Prof. Danton Cavalcanti Franco Junior – [email protected] – http://www.dantonjr.com.br 4.9.1. Exceptions mais Comuns As exceções mais comuns são: ArithmeticException: int i = 12 / 0; NullPointerException: ocorre quando se utiliza um objeto que não foi instanciado. NegativeArraySizeException: ocorre quando é atribuído um valor nulo para um array. ArrayIndexOutOfBoundsException: ocorre quando tenta-se acessar um elemento do array que não existe. 4.9.2. Categorias de Exceptions Há três grandes categorias de exceções em Java. De fato, a classe Java.lang.Throwable age como uma classe pai, para que todos os objetos disparados possam ser pegos nas exceptions. Deve-se evitar usar a classe Throwable, procure usar uma das três classes descritas a seguir: Erro: indica um problema sério de recuperação difícil, se não impossível; RuntimeException: problema ocorrido durante a implementação; Outra exceção: indica uma dificuldade durante a implementação que pode acontecer razoavelmente por causa de efeitos ambientais e pode se manipulado. 4.10. Definindo Classes A declaração de classe tem a seguinte sintaxe (as palavras entre colchetes são opcionais): [lista de modificadores] class NomeClasse [extends NomeSuperClasse][implements NomeInterface] { [declaração das variáveis] declaração de métodos; } Para definir uma classe use a palavra chave class e o nome da classe. Exemplo: class Minhaclasse { // Comandos da classe; } Se esta classe é uma subclasse de outra classe, use extends para indicar a superclasse. Exemplo: class Minhaclasse extends SuperClasse { // Comandos da classe; } 4.11. Definição de Métodos Os métodos de uma classe são as funções e os procedimentos implementados para a manipulação de dados. Todas as operações em dados devem ser implementadas em métodos. A definição dos métodos tem cinco partes básicas: O modificador. O nome do método. O tipo objeto ou tipo primitivo de retorno. Uma lista de parâmetros. O corpo do método. A definição básica de um método tem esta aparência: [comentário] [modificador] TipoRetorno NomeMétodo(tipo1 arg1, tipo2 arg2, ...) { // Definições do método; } Apostila de Java Página 19 de 25 Prof. Danton Cavalcanti Franco Junior – [email protected] – http://www.dantonjr.com.br 4.12. A Palavra this O comando this é uma palavra chave usada num método como referência para o objeto corrente, ela tem o significado de: “o objeto para o qual este trecho de código está sendo executado”. Suponha uma classe que possui a seguinte declaração de atributo: public int qualquer;. Se quisermos em um método desta classe alterar o atributo qualquer para o valor 3, basta escrever qualquer=3;, mas este código escrito dentro de um método da classe que declara qualquer, é totalmente equivalente a this.qualquer=3;, sendo o último uma opção mais clara e capaz de eliminar ambigüidades entre os nomes dos atributos de uma classe e os nomes dos argumentos de um dos métodos desta (quando estes nomes forem iguais). O uso de this também é válido fazer para chamadas de métodos para o objeto corrente. Por exemplo: class Pessoa { String nome; int idade; Pessoa(String nome, int idade) { this.nome = nome; this.idade = idade; } public void imprimeDados() { System.out.print(“Nome: “ + this.nome + “ Idade: “ + this.idade); } } 4.13. Modificadores Na linguagem Java pode-se utilizar algumas palavras-chave para modificar o modo como são declaradas as classes, os métodos e as variáveis. Para classes, existem apenas dois modificadores de acesso. Ao omitir o nome do modificador em sua declaração, temos o chamado default ou package, que indica que a classe estará visível para qualquer outra classe que esteja dentro do mesmo pacote. A outra opção é deixar o acesso public, permitindo que todas as classes tenham acesso a esta classe. Para acessar uma classe public que esteja em um pacote diferente, é necessário fazer o import ou utilizar seu nome completo. Há também outros modificadores que podem ser utilizados para classes. O strictfp força todos os métodos a aderirem às regras IEE754, tornando possível saber exatamente como números float e double irão se comportar, de forma independente da plataforma. O final impede que a classe seja herdada, sendo utilizado para impedir o overriding, ou seja, que os métodos sejam sobrescritos por subclasses e depois utilizados como se fossem da super classe através de polimorfismo. É utilizado em algumas classes da API do Java, como a String, para podermos sempre confiar em seu comportamento. Porém vai contra os princípios de orientação a objeto e por isso só deve ser utilizado quando realmente necessário. O abstract significa justamente o contrário, pois neste caso a classe não pode ser instanciada, sendo possível apenas herdar esta classe para utilizá-la através de uma subclasse. 4.13.1 Os Modificadores de Acesso de Métodos e Variáveis Antes de iniciar a explicação sobre os modificadores de variáveis, é necessário entender que existem dois tipos delas: Variáveis de instância: são campos do objeto, declarados fora de qualquer método e inicializados quando é instanciado um objeto da classe. Também são chamadas de campos, propriedades ou atributos. Variáveis locais: são as declaradas dentro de um método. Seu ciclo de vida está relacionado ao seu escopo (no máximo o do método) e elas sempre ficam no stack12. Antes de tentar utilizá-las é necessário inicializá-las explicitamente, em uma parte atingível do 12 Stack nada mais é do que a famosa pilha do processo, ela é responsável em armazenar informações temporariamente de uma variável local ou ate mesmo do RET (return address). Apostila de Java Página 20 de 25 Prof. Danton Cavalcanti Franco Junior – [email protected] – http://www.dantonjr.com.br código (fora de um if, por exemplo), senão o compilador retornará um erro. Variáveis locais também são chamadas de variáveis de stack, temporárias, automáticas ou de método. É permitido que uma variável local tenha o mesmo nome de uma variável de instância. Neste caso, utilize a referência this para acessar a variável de instância. Métodos e variáveis de instância são chamados de "membros" e podem utilizar modificadores de acesso, ao contrário de variáveis locais. Porém, se a classe em si não estiver visível para outra classe, seus membros também não estarão visíveis, independentemente de qualquer modificador utilizado neles. Os modificadores de acesso aplicáveis são: public: qualquer classe pode acessar. private: não pode ser acessado por nenhuma outra classe. Como não é visto pelas subclasses, não se aplica regras de overriding. default (não declarando explicitamente nenhum dos outros modificadores): acessível somente por classes do mesmo pacote. protected: acessível por classes do mesmo pacote ou através de herança. Os membros herdados não são acessíveis a outras classes fora do pacote em que foram declarados. Existem ainda outros modificadores de métodos: final: impede que o método seja sobrescrito (overriding) na subclasse (a classe não deve ser estendida – protege funções). Ele também pode ser utilizado nos argumentos do método, significando que estes não poderão ter seu valor ou referência alterados. abstract: indica que método não foi implementado (a classe tem de ser estendida – para ser útil). Neste caso é necessário utilizar ponto e vírgula ao invés das chaves na sua declaração. Existindo algum método abstrato, a classe também deve ser declarada abstrata. A primeira subclasse concreta será obrigada a implementar os métodos abstratos, seguindo exatamente a mesma assinatura do método. Métodos abstratos não podem ser static, final, private, synchronized, strictfp ou native. synchronized: só pode ser acessado por uma thread de cada vez. native: indica que o método é implementado em uma linguagem dependente de plataforma. strictfp: força o método a aderir as regras IEE754, como explicado para as classes. No caso de variáveis, o modificador final impossibilita que a variável seja reinicializada com outro valor. Se a variável for de instância, é necessário fornecer um valor na hora de declará-la ou em todos os construtores da classe, caso contrário ocorrerá um erro de compilação. Variáveis de interface sempre são final e precisam ter seu valor declarado. Outros modificadores do Java são: transient: é aplicável apenas a variáveis de instância, e faz a JVM ignorar a variável quando tenta serializar seu objeto. volatile: também só é aplicável a variáveis de instância e indica que uma thread acessando esta variável precisa sempre sincronizar o valor de sua cópia local com a cópia principal da memória. static: variáveis e métodos marcados como static pertencem à classe, ao invés de a alguma instância particular. É possível utilizá-los sem existir nenhuma instância da classe, chamando diretamente pelo nome da classe. Quando há instâncias, a variável static irá ser compartilhada entre todas elas, existindo apenas uma cópia por classe. Métodos static não conseguem acessar diretamente variáveis ou métodos que não sejam static, pois eles pertencem a classe e não saberiam de qual instância utilizar. Por isso, é necessário instanciar um objeto e utilizá-lo explicitamente neste caso. Métodos static também não podem ser overriden. Coisas que podem ser marcadas como static: o métodos; o variáveis de instância; o classes aninhadas de nível superior. Coisas que não podem ser marcadas como static: o construtores; o classes; o interfaces, o inner classes (incluindo seus métodos e variáveis); o variáveis locais. O modificador pode ser um ou mais, de um abstract, final ou public (abstract e final são opostos e não são permitidos juntos) Apostila de Java Página 21 de 25 Prof. Danton Cavalcanti Franco Junior – [email protected] – http://www.dantonjr.com.br 4.14. Polimorfismo O polimorfismo (muitas formas) consiste na utilização de um mesmo nome para métodos diferentes. Há duas formas: Sobrecarga: utiliza-se o mesmo nome para métodos diferentes (de preferência correlatos) os quais serão identificados pelo número de parâmetros e/ou pelos tipos destes. Resolvido em tempo de compilação. Sobreposição: é resolvido em tempo de execução e a interface dos métodos é absolutamente igual, ou seja, possuem o mesmo número e tipos de parâmetros. Caso aconteça, o método da classe derivada (subclasse) precede o método da superclasse. Abaixo temos um exemplo de polimorfismo: public class Calculadora { static int Soma() { return 0; } static int Soma(int Valor) { return Valor + Valor; } static int Soma(int Valor1, int Valor2) { return Valor1 + Valor2; } public static void main(String [] args) { System.out.println(Soma()); System.out.println(Soma(5)); System.out.println(Soma(5, 7)); } } 4.15. Construtores e Finalizadores A instanciação é efetivada com a utilização de um construtor, o qual é um método especial que inicializa o objeto criado. Ele é necessário para preencher os valores iniciais da classe, pois esta pode conter informações (dados) privadas – que não são acessíveis fora do escopo da classe, marcados por uma palavra-chave. O construtor é um método que possui o mesmo nome da classe e pode receber parâmetros. É comum as classes possuírem ao menos um construtor. Caso possuam mais de um, a distinção é feita pelo número e tipo dos parâmetros, num caso típico de overloading (sobrecarga) de funções. O exemplo a seguir, ilustra a especificação de um construtor para a classe Carro: class Carro { int capacidade_tanque; double consumo_medio; Carro (int capacidade, double consumo) { capacidade_tanque = capacidade; consumo_medio = consumo; } double autonomia() { return capacidade_tanque * consumo_medio; } } Apostila de Java Página 22 de 25 Prof. Danton Cavalcanti Franco Junior – [email protected] – http://www.dantonjr.com.br Por sua vez, o finalizador é um método que é chamado nos momentos finais dessa classe, antes que a memória ocupada por ela seja liberada. Ele é opcional e, quando definido, não há garantias de que ele será chamado. É garantido que ele foi executado antes da memória ser reutilizada, mas não é garantida a liberação do armazenamento não utilizado. O exemplo a seguir mostra a definição do finalizador para a classe Carro: class Carro { int capacidade_tanque; double consumo_medio; Carro (int capacidade, double consumo) { capacidade_tanque = capacidade; consumo_medio = consumo; } double autonomia() { return capacidade_tanque * consumo_medio; } protected void finalize() { // Código do finalizador } } O finalizador deve seguir rigidamente esta declaração (protected, void e sem parâmetros). Cabe notar que o processo de reutilização de memória (garbage collector) é diferente do C++, onde o programador especifica e invoca explicitamente o método que liberará a memória que a classe utilizou. Em Java a gerência da memória disponível para execução e, conseqüentemente, da memória não mais utilizada é feita automaticamente quando o sistema detecta falta de memória ou explicitamente através de uma chamada ao método System.gc(); em qualquer ponto do programa. O objetivo dos finalizadores é possibilitar a liberação de recursos, como descritores de arquivos, que são utilizados por objetos mas não podem ser acessados diretamente. 4.16. Encapsulamento As operações executadas sobre as informações são tão importantes quanto estas. O encapsulamento consiste em agrupar, de algum modo, as informações e as operações. Desse modo, podemos identificar prontamente as informações e o que podemos fazer sobre elas, forçando a integridade do tipo de dados, por definir uma maneira apropriada de acesso ao dado do tipo. Em POO 13, este tipo de dados (informações e operações permitidas) é denominado classe, às informações elementares denominam-se campos (ou atributos), às operações sobre estas informações são chamadas de métodos, e uma variável definida como sendo de uma classe é chamado instância ou objeto. É semelhante a definição de um de tipo comum, exceto pelo fato de que as operações permitidas estão anexadas a ela. O suporte ao conceito de encapsulamento permite agrupar a definição das informações a serem armazenadas com todas as operações possíveis sobre elas. O exemplo a seguir ilustra a implementação do conceito com a definição de uma classe com os campos e os métodos. class Carro { int capacidade_tanque; float consumo_medio; float autonomia() { return capacidade_tanque * consumo_medio; } } A declaração de uma variável como sendo da classe Carro: Carro Palio; 13 POO – Programação orientadas à Objetos, é um tipo de programação onde os programas são feitos de forma a tentar representar o tipo e relação entre entidades (objetos) do mundo real. As funções e tratamento de dados são encapsulados em módulos que descrevem os objetos e as funções que eles suportam. A execução de programas se dá através da troca de mensagens entre as entidades previamente definidas. Permite a execução de sistemas altamente modulares, com grande flexibilidade e aproveitamento (ou aquisição) de módulos anteriormente desenvolvidos. O exemplo mais conhecido é a linguagem Java e o Delphi. Apostila de Java Página 23 de 25 Prof. Danton Cavalcanti Franco Junior – [email protected] – http://www.dantonjr.com.br A variável declarada como sendo de uma classe recebe o nome de objeto daquela classe. No caso anterior, Palio é um objeto da classe Carro. O acesso aos campos da classe e a chamada ao método autonomia() são escritos em uma notação própria, que utiliza o nome do objeto, como no exemplo a seguir: // uma atribuição de valor ao campo capacidade_tanque do objeto Palio Palio.capacidade_tanque = 52; // a chamada ao método autonomia() do objeto Palio Palio.autonomia(); Como resultado deste modo de acesso aos objetos da classe, conceitualmente temos, para os tipos (classes) definidos pelo usuário, mesma situação que os tipos internos (primitivos) da linguagem (por exemplo, inteiros) em que o compilador sabe quais as operações que podem ser feitas sobre determinado tipo. Assim, o código construído é mais confiável e pode ser depurado mais rapidamente, pois os modos de alteração dos dados são disciplinados. 4.17. Operador new O operador new é utilizado sempre que é necessário criar uma nova instância de uma classe (objeto). Este operador tem um funcionamento parecido como o malloc() da linguagem C, alocando espaço em memória para a adequação do novo objeto. 5. Referências Esta apostila é uma compilação de outras apostilas, sites na internet, livros e material do próprio autor. Para críticas, sugestões, elogios, ou “bugs” encontrados, favor contatar: Danton Cavalcanti Franco Junior [email protected] http://www.dantonjr.com.br icq: 3438321 msn: [email protected] Se você desejar usar essa apostila, apenas referencie o endereço acima. 6. Anexos Alguns conceitos e dicas importantes ao se trabalhar com Java e POO. 6.1. Conceitos da POO A Orientação a Objeto é um paradigma de análise, projeto e programação de sistemas de software baseado na composição e interação entre diversas unidades de software chamados objetos (Em alguns contextos, prefere-se usar modelagem orientada ao objeto, em vez de projeto). A análise e projeto orientados a objetos têm como meta identificar o melhor conjunto de objetos para descrever um sistema de software. O funcionamento deste sistema se dá através do relacionamento e troca de mensagens entre estes objetos. É uma forma especial de programar, mais próximo de como expressaríamos as coisas na vida real do que outros tipos de programação. Com a POO temos que aprender a pensar as coisas de uma maneira distinta, para escrever nossos programas em termos de objetos, propriedades, métodos e outras coisas que veremos rapidamente para esclarecer conceitos e dar uma pequena base que permita soltarmos um pouco com este tipo de programação. A utilização de UML14 é muito comum no projeto de sistemas orientados a objetos. Na programação orientada a objetos, implementa-se um conjunto de classes que definem os objetos presentes no sistema de software. Cada classe determina o comportamento (definidos nos métodos) e estados possíveis (atributos) de seus objetos, assim como o relacionamento com outros objetos. Smalltalk, Perl, Python, C++, Java e C# são as linguagens de programação mais importantes com suporte à orientação a objetos. 14 UML – Unified Modeling Language(Linguagem de Modelagem Unificada), é uma linguagem de modelagem não proprietária de terceira geração. É um método aberto usado para especificar, visualizar, construir e documentar os artefatos de um sistema de software orientado a objetos. Apostila de Java Página 24 de 25 Prof. Danton Cavalcanti Franco Junior – [email protected] – http://www.dantonjr.com.br 6.1.1. Classes As classes são declarações de objetos, também se poderiam definir como abstrações de objetos. Isto quer dizer que a definição de um objeto é a classe. Quando programamos um objeto e definimos suas características e funcionalidades na verdade o que estamos fazendo é programar uma classe. Uma classe define o comportamento de seus objetos através de métodos e os estados possíveis destes objetos através de atributos. 6.1.2. Objeto Um objeto é qualquer estrutura modular que faz parte de um produto. Uma janela, por exemplo, é um objeto de uma casa, de um carro ou de um software com interface gráfica para o usuário. Objetos são classes instanciadas. 6.1.3. Atributos Os atributos são as características do objeto, como cor e tamanho, a janela, por exemplo, tem atributos como o modelo, tamanho, abertura simples ou dupla, entre outros. 6.1.4. Encapsulamento O encapsulamento é um mecanismo interno do objeto "escondido" do usuário. Uma pessoa pode abrir uma janela girando a tranca sem precisar saber o que há dentro dela. 6.1.5. Ação A ação é a operação efetuada pelo objeto. Todas as janelas, por exemplo, controlam a iluminação e temperatura ambiente, dependendo do seu design. 6.1.6. Método Os métodos são as implementações dos códigos que irão realizar as ações das classes. Verbos são fortes candidatos a serem métodos. 6.1.7. Herança Herança diz que um objeto novo nem sempre é criado do zero. Ele pode "herdar" atributos e ações de outros já existentes. Um basculante herda atributos das janelas e das persianas, ou um funcionário herda as características de uma pessoa. 6.1.8. Polimorfismo Polimorfismo15 vem do grego: muitas formas. É a capacidade de objetos diferentes reagirem segundo a sua função a uma ordem padrão, ou seja, a capacidade de um operador executar a ação apropriada dependendo do tipo do operando. Aqui operando e operador, estão definidos num sentido mais geral: operando pode significar argumentos atuais de um procedimento e operador o procedimento, operando pode significar um objeto e operador um método, operando pode significar um tipo e operador um objeto deste tipo. O comando "abre", por exemplo, faz um objeto entrar em ação, seja ele uma janela, uma porta ou uma tampa de garrafa. 6.1.9. Ligação Ligação é quando um objeto conecta a sua ação a outro. Um sensor de claridade, por exemplo, ativa o acendimento automático da iluminação de rua. 6.1.10. Embutimento O embutimento permite a um objeto incorporar funções de outros, como um liquidificador que mói carne com a mudança do tipo da lâmina. 15 Veja o tópico 4.14., para o exemplo de uma implementação de polimorfismo em Java. Apostila de Java Página 25 de 25