java se em portugues excelente apostila curso completo de introdução a java se

257
Java Fundamentals

Upload: luizc12

Post on 08-Jun-2015

2.883 views

Category:

Documents


44 download

TRANSCRIPT

Page 1: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Java Fundamentals

Page 2: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE
Page 3: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Java Fundamentals

I

SumárioSumárioSumárioSumário

1.1.1.1. A tecnologia Java e configuração do ambieA tecnologia Java e configuração do ambieA tecnologia Java e configuração do ambieA tecnologia Java e configuração do ambientententente........................................................ 1111----1111

Objetivos .......................................................................................................................1-2 O que é Java? .............................................................................................................1-3 Simples e orientada a objetos ...................................................................................1-5 Uma linguagem robusta.............................................................................................1-7 Multiplataforma e interpretada ................................................................................1-9 A Java Virtual Machine - JVM .................................................................................1-11 Uma Linguagem Segura e Dinâmica.....................................................................1-14 Aspectos de segurança ...........................................................................................1-16 O Just in Time Compiler - JIT .....................................................................................1-18 O Java Standard Development Kit – J2SDK..........................................................1-19 Configurando o ambiente.......................................................................................1-22 API’s da linguagem ...................................................................................................1-23

2.2.2.2. Tipos e OTipos e OTipos e OTipos e Operadoresperadoresperadoresperadores ................................................................................................................................................................................................................ 2222----1111

Objetivos .......................................................................................................................2-2 Variáveis ........................................................................................................................2-3 Tipos primitivos e tipos compostos ............................................................................2-4 Tipos Primitivos ..............................................................................................................2-6 Declarando um tipo primitivo..................................................................................2-10 Tipo caracter – char..................................................................................................2-12 Tipo booleano – boolean.........................................................................................2-14 Tipos inteiros - byte, short, int e long .......................................................................2-15 Tipos de ponto flutuante - float e double..............................................................2-17 Tipo composto – String..............................................................................................2-19 Conversões de tipos – casting.................................................................................2-20 Tipos de referência....................................................................................................2-22 Expressões e operadores..........................................................................................2-23 Sumário de operadores............................................................................................2-25 Precedência...............................................................................................................2-27 Associatividade..........................................................................................................2-28 Tipos de operadores: unários e binários ................................................................2-29

3.3.3.3. Criando classes e objetosCriando classes e objetosCriando classes e objetosCriando classes e objetos ............................................................................................................................................................................ 3333----1111

Objetivos .......................................................................................................................3-2 Classes e Objetos.........................................................................................................3-3 Criando uma classe ....................................................................................................3-4 Padrões..........................................................................................................................3-6

Page 4: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Java Fundamentals

II

Criando e importando pacotes................................................................................3-9 Static import................................................................................................................3-11 Criando objetos .........................................................................................................3-12 O que é a referência null? .......................................................................................3-13 Atribuindo referências...............................................................................................3-15 Visibilidade aplicada a classes ...............................................................................3-16 Definindo operações ................................................................................................3-18 Comando return ........................................................................................................3-21 Visibilidade para operações ...................................................................................3-22 Definindo atributos ....................................................................................................3-25 Visibilidade aplicada a atributos ............................................................................3-26 Acessando atributos .................................................................................................3-32 Comentários no código fonte.................................................................................3-33 Escopo das variáveis.................................................................................................3-36 Passando Tipos Primitivos para Métodos ...............................................................3-39 Passando Referências para Métodos ....................................................................3-40 Exercícios.....................................................................................................................3-42

4.4.4.4. Comandos da LinguagemComandos da LinguagemComandos da LinguagemComandos da Linguagem ............................................................................................................................................................................ 4444----1111

Objetivos .......................................................................................................................4-2 Comandos ....................................................................................................................4-3 Comando if / else / else if ..........................................................................................4-4 Seqüência de Cláusulas else if ..................................................................................4-7 Operador ternário .......................................................................................................4-9 Comando switch .......................................................................................................4-10 Comando while .........................................................................................................4-13 Comando do .............................................................................................................4-14 Comando for..............................................................................................................4-15 Comando “for-each” ...............................................................................................4-18 Comando break ........................................................................................................4-19 Comando continue ..................................................................................................4-21 Exercícios.....................................................................................................................4-24

5.5.5.5. Aprofundando o estudo sobre ClassesAprofundando o estudo sobre ClassesAprofundando o estudo sobre ClassesAprofundando o estudo sobre Classes.................................................................................................... 5555----1111

Objetivos .......................................................................................................................5-2 Visão Geral ...................................................................................................................5-3 Overloading – sobrecarga de operação ...............................................................5-4 Métodos construtores .................................................................................................5-6 Referência this..............................................................................................................5-9 Compartilhando código entre Construtores ........................................................5-11 Método destrutor – finalize() ....................................................................................5-12 Variáveis de instância...............................................................................................5-13 Métodos de instância ...............................................................................................5-15 Variáveis de classe ....................................................................................................5-16 Inicializando Variáveis de Classe ............................................................................5-19 Métodos de classe ....................................................................................................5-20

Page 5: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Java Fundamentals

III

Exemplos de variáveis e métodos estáticos .........................................................5-22 O mecanismo de herança entre classes ..............................................................5-23 Herdando estrutura e comportamento.................................................................5-24 Especificando herança em Java ...........................................................................5-25 Objetos de subclasses...............................................................................................5-26 Chamando construtores da superclasse...............................................................5-27 Overloading e Overriding de métodos..................................................................5-29 Redefinindo métodos – overriding..........................................................................5-30 Referência super........................................................................................................5-33 Invocando métodos da superclasse......................................................................5-35 Visibilidade protected ..............................................................................................5-36 Varargs ........................................................................................................................5-37 Polimorfismo................................................................................................................5-39 Modificador final........................................................................................................5-41 Enums...........................................................................................................................5-43 Exercícios.....................................................................................................................5-46

6.6.6.6. Coleções, Arrays, Strings, e Wrapper ClassesColeções, Arrays, Strings, e Wrapper ClassesColeções, Arrays, Strings, e Wrapper ClassesColeções, Arrays, Strings, e Wrapper Classes ............................................................ 6666----1111

Objetivos .......................................................................................................................6-2 Strings .............................................................................................................................6-3 Criando Strings .............................................................................................................6-4 Concatenando Strings................................................................................................6-5 Executando operações em objetos String..............................................................6-6 Comparando duas Strings .........................................................................................6-8 Obtendo strings a partir de objetos..........................................................................6-9 Convertendo tipos primitivos em strings ................................................................6-10 Wrapper Classes ........................................................................................................6-11 Conversões com Wrapper Classes .........................................................................6-12 StringBuffer e StringBuilder ........................................................................................6-13 Arrays ...........................................................................................................................6-14 Arrays de tipos primitivos ..........................................................................................6-15 Declarando arrays de tipos primitivos....................................................................6-16 Criando arrays............................................................................................................6-17 Inicializando arrays ....................................................................................................6-18 Arrays de objetos .......................................................................................................6-20 Declarando arrays de objetos ................................................................................6-21 Inicializando arrays de objetos................................................................................6-22 Utilizando arrays de objetos .....................................................................................6-23 Arrays e Exceções......................................................................................................6-24 Arrays multidimensionais...........................................................................................6-25 O método main(String[] args) ........................................................................6-26

API Colletion ...............................................................................................................6-27 A interface Iterator ....................................................................................................6-28 A interface Enumeration ..........................................................................................6-29 Interfaces do framework ..........................................................................................6-30 A classe ArrayList........................................................................................................6-31 A classe Vector ..........................................................................................................6-32

Page 6: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Java Fundamentals

IV

A classe Hashtable ....................................................................................................6-34 A classe LinkedList......................................................................................................6-35 Generics ......................................................................................................................6-36 Autoboxing .................................................................................................................6-39 Exercícios.....................................................................................................................6-43

7.7.7.7. Tratamento de ExceçõesTratamento de ExceçõesTratamento de ExceçõesTratamento de Exceções.................................................................................................................................................................................... 7777----1111

Objetivos .......................................................................................................................7-2 Introdução ....................................................................................................................7-3 1a Vantagem: Separação de Código.....................................................................7-4 2a Vantagem: Propagação de Erros........................................................................7-6 3a Vantagem: Agrupar Tipos de Erros ......................................................................7-8 4a Vantagem: Exceções não são Ignoradas........................................................7-10 Manipulando Exceções............................................................................................7-11 Tratando Exceções....................................................................................................7-13 Manipulando Exceções............................................................................................7-14 Manipulando Exceções: Exemplo Prático.............................................................7-16 Propagando Exceções.............................................................................................7-17 Lançando Exceções .................................................................................................7-18 Criando Exceções .....................................................................................................7-19 Capturando Exceções e Levantando Exceções Diferentes..............................7-20 Exercícios.....................................................................................................................7-22

8.8.8.8. Classes abstratas e InterfacesClasses abstratas e InterfacesClasses abstratas e InterfacesClasses abstratas e Interfaces .................................................................................................................................................... 8888----1111

Objetivos .......................................................................................................................8-2 Abstração .....................................................................................................................8-3 Definindo classes abstratas........................................................................................8-4 Métodos Abstratos.......................................................................................................8-6 Definindo métodos abstratos ....................................................................................8-7 Interfaces ......................................................................................................................8-8 Exemplos de interfaces...............................................................................................8-9 Definindo Interfaces ..................................................................................................8-10 Implementando Interfaces ......................................................................................8-11 Exercícios.....................................................................................................................8-13

Page 7: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Java Fundamentals

1-1

11.. AA tteeccnnoollooggiiaa JJaavvaa ee ccoonnffiigguurraaççããoo ddoo aammbbiieennttee

Page 8: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

A tecnologia java e configuração do ambiente

1-2

Objetivos

• Compreender os fundamentos da tecnologia Java

• Discutir vantagens da tecnologia

• Entender o funcionamento da JVM (Java Virtual Machine)

• Configurar o ambiente de desenvolvimento para o programador

Page 9: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

A tecnologia java e configuração do ambiente

1-3

O que é Java?

• Linguagem orientada a objetos, simples, portável, interpretada, distribuída, robusta, segura, dinâmica, de alto desempenho, multi-thread e independente de plataforma

• Projetada pela Sun Microsystems inicialmente para dispositivos eletrônicos

• Utilizada posteriormente em navegadores web, para permitir que uma aplicação pudesse ser desenvolvida e “executada na web”. Aqui é o nascimento da tecnologia applet

• Uma linguagem muito utilizada atualmente para desenvolvimento de sistemas que precisam rodar na web bem como sistemas desktop

Breve Histórico

Java começou em 1991, quando um grupo de analistas da Sun, liderados por Patrick Naughton e James Gosling, procurou desenvolver uma linguagem de computador que fosse usada em equipamentos domésticos, tais como comutadores de canais para TV a cabo, videocassetes e outros.

Como estes equipamentos não dispõem de muita memória ou velocidade, a linguagem tinha de ser reduzida e gerar código eficiente. Além disto, como diferentes fabricantes poderiam escolher diferentes CPUs, tal linguagem não poderia se restringir a uma única arquitetura.

O projeto ficou conhecido como Green Project.

DUKE, um dos símbolos do Java

Visando satisfazer todas estas exigências, a equipe de analistas optou por uma linguagem que gerasse código intermediário (os famosos bytecodes Java), e que a interpretação deste código não fosse feita diretamente pelo hardware e sim por uma máquina virtual disposta sobre ele (conhecida hoje como JVM – Java Virtual Machine).

Esta linguagem foi batizada inicialmente com o nome Oak (que, em português significa carvalho). Possivelmente o nome escolhido por Gosling se deve a um carvalho que existia em frente a sua janela na Sun MicroSystems.

Page 10: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

A tecnologia java e configuração do ambiente

1-4

Posteriormente se descobriu que Oak já era o nome de uma outra linguagem, e o nome foi então trocado para Java.

Java não obteve muito sucesso como linguagem de controle de eletrodomésticos (e isto nós podemos muito bem atestar :-). Em vão, a equipe do Green Project tentou vender a idéia para fabricantes de tais dispositivos. Dissolvida a equipe, por absoluta falta de êxito econômico, alguns dos antigos componentes perceberam que uma das possíveis utilidades para tal linguagem seria embuti-la em navegadores, como os encontrados no mercado.

Tais aplicativos exigiam justamente uma linguagem independente de plataforma, confiável, segura e em tempo real: todas as características “estranhas” que Java possuía.

Page 11: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

A tecnologia java e configuração do ambiente

1-5

Simples e orientada a objetos

• Uma linguagem simples e orientada a objetos

• Baseada em Smalltalk e C++

• A tecnologia de objetos para esta linguagem foi baseada em Smalltalk

• Reaproveitou grande parte da sintaxe utilizada pelo C e C++

• Eliminou construções de C++ consideradas complexas ou desnecessárias

• Reduzido conjunto de palavras reservadas e um grande poder de expressão

Uma Linguagem Orientada a Objetos

Problemas surgidos na área de engenharia de software, tais como aumento explosivo da complexidade dos sistemas, dificuldades na manutenção e evolução dos softwares existentes, fraca robustez apresentada pelos aplicativos e outros, fizeram com que os paradigmas de análise e desenvolvimento de software fossem alterados.

Java surge junto com o “boom” da orientação por objetos, à ampla aceitação deste paradigma pelos técnicos de informática como o mais adequado a enfrentar os problemas encontrados.

A cultura dos técnicos da equipe de desenvolvimento da Sun Microsystems fez com que, entre as linguagens orientadas por objetos conhecidas, escolhessem C++ como modelo para o desenvolvimento de Java. C++ era então uma das mais difundidas linguagens de programação orientada por objetos em voga no mundo UNIX.

Mas C++ era complexa demais. Várias construções em C++ eram de questionável utilidade e de difícil implementação por parte dos construtores de compiladores.

Herança múltipla e sobrecarga de operadores, por exemplo, eram construções que demandavam grande esforço por parte dos implementadores e que não fazem parte do núcleo mínimo exigido pelo paradigma. Desta forma alguns recursos ficaram de fora e decidiu-se manter inicialmente uma gama menor de recursos para viabilizar o projeto e manter o mesmo mais somples. Atualmente alguns recuros mais sofisticados como “Generics” foram incluídos. Os recursos básicos que foram atendidos na época são:

• Abstração

Page 12: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

A tecnologia java e configuração do ambiente

1-6

• Encapsulamento

• Herança

• Polimorfismo

Decidiram então simplificar:

• A linguagem não seria compilada para uma plataforma nativa e sim para uma máquina virtual. Esta técnica que dá ao java a possibilidade de rodar em múltiplas plataformas foi baseada no Smalltalk

• Não haveria programação genérica (na época, mas a partir da versão 1.5 este recurso já é suportado)

• Não haveria sobrecarga de operadores

• Herança múltipla seria substituída pelo mecanismo de interfaces, mais simples e com poder de expressão equivalente

• A velha sintaxe, tomada de empréstimo da linguagem C, seria enxugada, de modo a conter somente as palavras reservadas necessárias

Destas idéias iniciais surge então a tecnologia Java. Claro que há muito mais coisas presentes no java do que as listadas acima. Atualmente o java é uma tecnologia tão completa que permite você desenvolver aplicações para rodar na Web, em máquinas cliente, Celulares, Palm Tops e muito mais.

Page 13: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

A tecnologia java e configuração do ambiente

1-7

Uma linguagem robusta

• Java é uma linguagem fortemente tipada

• Ampla verificação de erros e checagem de tipos em tempo de compilação

• Não existem apontadores na linguagem

• Linguagem multiplataforma

• Gerência automática da memória (garbage collection)

Erro de Ponteiro?

Um dos principais objetivos dos projetistas da linguagem era conseguir conciliar a flexibilidade e o poder da orientação por objetos com a segurança e a robustez da checagem de tipos e erros em tempo de compilação.

Java é uma linguagem fortemente tipada.

E o que queremos dizer com isto?

Que, em tempo de compilação, são checados todos os problemas referentes à passagem de parâmetros e atribuições de variáveis no que diz respeito à compatibilidade de tipos entre a variável que recebe o valor e a variável atribuída.

Outra importante característica da linguagem Java é fato de não possuir apontadores, com o sentido que tal termo possui em C ou em C++.

Em C ou C++ é perfeitamente possível navegarmos despreocupadamente pela memória do processo: basta, para tal, declararmos um apontador para uma região de memória e sairmos a incrementá-lo ou decrementá-lo.

Toda a aritmética com apontadores não só é permitida pela linguagem, como também incentivada.

Em Java não há apontadores explícitos, nem tampouco aritmética de apontadores, mas sim referências feitas a objetos criados.

Objetos são criados através do operador new e o espaço de memória que ocupam é automaticamente gerenciado por um sistema de coleta de lixo (garbage collection) , que o libera tão logo não haja mais referências a um objeto.

Page 14: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

A tecnologia java e configuração do ambiente

1-8

Com isto, não existem em Java os erros de ponteiro (dangling pointers, memory leak e outros) tão conhecidos de linguagens como C e C++.

Page 15: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

A tecnologia java e configuração do ambiente

1-9

Multiplataforma e interpretada

Ao contrário das outras tecnologias onde os programas são compilados para um sistema operacional específico, os fontes Java são compilados para uma máquina virtual. Isto significa que após a compilação os mesmos, são executados por uma máquina virtual (JVM) e não diretamente pelo sistema operacional. Abaixo veja a forma tradicional de compilação dos programas e mais abaixo a forma como funciona o Java.

Figura 1-1: Compilação em C++.

Em linguagens tradicionais como C, C++ ou pascal, o código fonte é convertido para um conjunto de instruções de máquina da plataforma de hardware onde a compilação teve lugar. Este programa é executado diretamente pela CPU da máquina e está vinculado à plataforma em que foi compilado: só poderá ser executado por CPUs que compartilhem o mesmo conjunto de instruções, o que geralmente significa ficar limitado a um determinado fabricante de hardware ou a uma família de produtos.

Figura 1-2: Compilação em Java.

Page 16: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

A tecnologia java e configuração do ambiente

1-10

Java adota uma filosofia diferente. Os fontes Java não são convertidos diretamente para instruções de máquina. Ao contrário, a partir da compilação dos fontes são gerados arquivos contendo código intermediário que independe de plataforma.

O código intermediário Java, conhecido como “bytecode” Java, foi projetado para uma máquina hipotética. Contém instruções similares a de uma máquina real (operações aritméticas, controle de fluxo, etc.), mas não tem em vista, e nem se limita, a uma determinada arquitetura de computador.

Em vez de ser executado diretamente pelo hardware, este código é interpretado por uma JVM (Máquina Virtual Java Java Virtual Machine). Desta forma, em qualquer arquitetura onde exista uma JVM será possível executar um programa Java sem a necessidade de se re-compilar os fontes.

Os binários Java (código intermediário ou Java bytecode) são independentes de plataforma ou, dito de outra maneira, neutros quanto à arquitetura da máquina.

Os fontes Java são armazenados em arquivos com a extensão .java. A compilação dos arquivos .java trará como resultado arquivos com a extensão .class.

Arquivos com a extensão .class contém somente Java bytecodes e são também conhecidos como binários Java. Cabe novamente ressaltar que os binários Java (arquivos .class) não são executados diretamente pelo hardware e sim interpretados pela JVM.

Sem a JVM não há como executar nenhum programa Java.

Page 17: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

A tecnologia java e configuração do ambiente

1-11

A Java Virtual Machine - JVM

• Camada intermediária e isolante entre o sistema operacional e as aplicações Java.

• Elimina a dependência do código quanto à arquitetura e quanto às facilidades do SO.

• Responsável pela interpretação dos bytecodes Java.

• Traduz os bytecodes em instruções de máquina e em chamadas de sistema (API do SO).

• Pode ser implementada através de um programa avulso ou estar embutida em um navegador (Browser).

A máquina virtual Java (ou, como é comumente chamada, JVM, Java Virtual Machine) integra o ambiente de programação e execução Java. Ela é responsável por interpretar os bytecodes Java e traduzi-los em instruções reais de máquina e em chamadas de sistema (syscalls).

Figura 1-3: Esquema de independência da JVM.

Desta forma, as requisições feitas por um programa Java a recursos do sistema são mapeadas pela JVM em requisições feita ao SO sobre o qual a JVM executa. O SO responde a tais requisições e estas respostas são encaminhadas ao código Java em execução.

Uma vez compilado um programa Java, os binários (bytecodes Java) podem ser executados em toda a plataforma para a qual já a JVM já tenha sido portada. Atualmente, a grande maioria dos sistemas operacionais conhecidos possui uma implementação da JVM (Solaris, Windows98, WindowsNT, Linux, MacOS, HP-UX, AIX, etc.).

Page 18: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

A tecnologia java e configuração do ambiente

1-12

A JVM pode ser implementada através de um programa avulso, pode estar embutida em um navegador, fazer parte do núcleo de um banco de dados, ou mesmo integrar o kernel de um SO.

A única exigência que se faz à execução de um aplicativo Java é a existência da JVM para aquele ambiente.

Como executam os programas java

A linguagem Java é orientada a objetos, com linhas de execução (threads) dinâmicas e muitos outros recursos. Mas o que faz a diferença é o modo como os programas Java são executados. Eles rodam dentro de máquinas virtuais (virtual machines), que ficam dentro do computador. Por isso, um programa Java não tem contato com o computador real, ele conhece apenas a máquina virtual. Logo, os programas Java são independentes de plataforma. Se você já precisou desenvolver programas para vários sistemas operacionais, sabe que isso é uma grande vantagem.

Quando você escreve um programa Java e o compila, ele está pronto para ser executado em qualquer PC que contenha a máquina virtual Java. De certa forma, você está escrevendo para apenas uma plataforma: a máquina virtual.

A virtual machine determina o que os programas Java podem ou não fazer. Os programas escritos em linguagens compiladas, como C ou C++, são executados diretamente pelo sistema operacional. Assim sendo, eles têm acesso direto a todos os recursos do sistema, incluindo memória e sistema de arquivos. Como os programas Java são executados de dentro da máquina virtual, as pessoas (programadores e desenvolvedores) que criam a máquina virtual podem decidir o que um programa pode ou não fazer no computador. O ambiente criado para os programas Java chama-se ambiente de runtime. A máquina virtual age como um firewall (barreira) entre o computador e o programa Java. Um programa nunca acessa os dispositivos de entrada e saída, o sistema de arquivos ou mesmo a memória do seu computador. Em vez disso, ele pede que a máquina virtual faça isso.

Quando rodamos as applets, elas são descarregadas para uma máquina virtual que proíbe o acesso ao sistema de arquivos. Assim, ela só permite acesso indireto aos recursos do sistema.

Por ser uma linguagem interpretada, isso explica a independência de plataforma Java.

Page 19: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

A tecnologia java e configuração do ambiente

1-13

Por que interpretada?

Porque o compilador Java gera o bytecode (código especial Java), que será executado por uma máquina virtual implementada em software, chamada de JVM – Java Virtual Machine (Máquina Virtual Java).

A diferença entre o Java que é uma linguagem interpretada, comparada com uma linguagem compilada, como o caso do C ou C++ é que enquanto nessas linguagens tradicionais, para cada plataforma precisamos que o compilador gere um código especifico, como por exemplo, para um PC. Se quisermos que o mesmo programa rode em um Macintosh, precisaremos compilá-lo para rodar em Macintosh e assim por diante. Já com o Java isso não aconteceria, pois para rodarmos um programa feito em Java, usamos o interpretador Java (contido na JVM) para executar o bytecode resultante da compilação. Como o bytecode Java é independente de plataforma, os programas Java podem rodar em qualquer plataforma para a qual a JVM tenha sido portada. A JVM inclui o interpretador mais o sistema de runtime.

Em um ambiente interpretado, a fase de linkagem que existem no desenvolvimento de programas tradicionais compilados praticamente desaparece. O equivalente em Java à fase de linkagem consiste apenas do processo de carregar novas classes no ambiente de execução da JVM.

Esse é um processo leve e incremental, que ocorre em tempo de execução. Isso é diferente do ciclo compilar-linkar-rodar, mais trabalhoso, comum em linguagens como C e C++. O resultado é uma redução no tempo de desenvolvimento dos programas.

Agora, depois dessa explicação, fica claro o que eles quiseram dizer com a frase "Write once, Compile once and Run anywhere" – ("Escreva uma vez, compile uma vez e rode em qualquer lugar"), frase esta que se tornou uma das marcas registradas de Java.

Page 20: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

A tecnologia java e configuração do ambiente

1-14

Uma Linguagem Segura e Dinâmica

• Os bytecodes de Java são constantemente policiados pela JVM

• Instruções não autorizadas levantam exceções de segurança

• A carga das classes é feita de maneira dinâmica

• Uma classe pode ser carregada através da rede ou do disco local da máquina

Figura 1-4: Fluxo de compilação e execução de uma classe Java

Durante a execução de um programa Java, a JVM pode importar código de qualquer lugar. A fim de tornar, a linguagem segura, é necessário ou nos certificarmos de que o local de onde o código se origina é seguro, ou policiarmos constantemente o código inseguro contra eventuais violações de segurança.

A primeira opção é implementada através de sistemas de assinatura digital de código.

A segunda opção, por sua vez, é de responsabilidade do sistema de runtime. Cabe a este policiar a execução dos bytecodes Java, verificando se não há, entre eles, nenhuma instrução não autorizada, que viole as regras de segurança estabelecidas pela linguagem.

Page 21: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

A tecnologia java e configuração do ambiente

1-15

O carregador de classes do sistema de runtime assegura que classes com origem em uma fonte local (classes Built-in) e classes provenientes da rede sejam armazenadas separadamente.

Durante a execução, o sistema de runtime sempre procura resolver primeiro uma referência nas classes locais. Isto garante que classes locais não sejam substituídas por classes carregadas a partir da rede (fonte insegura).

Elimina a possibilidade de sobrescrita de classes seguras (spoofing) por classes não confiáveis. O acesso ao sistema de arquivos locais e aos recursos de rede é controlado por classes da linguagem (Built-in classes). Estas classes são restritivas por default. Se código importado e classificado como inseguro tenta acessar o sistema de arquivos, os mecanismos de segurança avisam imediatamente ao usuário.

Page 22: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

A tecnologia java e configuração do ambiente

1-16

Aspectos de segurança

Talvez pelo fato de Java estar fortemente associado à Internet, um dos aspectos mais divulgados da linguagem é sua segurança. Isso é natural: sem a certeza da segurança, provavelmente ninguém iria querer baixar código de um site desconhecido na Internet e deixar que ele rodasse em seu computador.E no entanto, isso já está sendo feito todos os dias com os applets Java.

Java foi projetado com a segurança em mente. Por isso, oferece várias camadas de controles de segurança que protegem contra código malicioso, permitindo que os usuários rodem tranqüilamente programas de origem desconhecida, como os applets.

No nível mais baixo, a segurança é uma conseqüência da robustez de Java. Como já vimos, os programas Java não podem forjar ponteiros para a memória, nem estourar arrays, nem ler memória que esteja fora das fronteiras de um array ou string. Esses recursos são uma das principais defesas de Java contra código malicioso. Ao impedir totalmente qualquer acesso direto à memória, toda uma enorme classe de ataques à segurança é evitada.

A segunda barreira contra código malicioso é o processo de verificação do bytecode que é executado pelo interpretador Java sobre qualquer código de origem desconhecida que é carregado. Essa verificação assegura que o código seja bem formado – isto é, que ele não avance na memória que fica acima ou abaixo dos limites da pilha (stack overflow ou underflow), nem implemente bytecode ilegal. Se esse passo de verificação do bytecode não existisse, código corrompido por incompetência ou má fé poderia tirar partido de pontos fracos na implementação de um interpretador Java.

Outra camada de proteção para segurança é comumente chamada de modelo de caixa de areia (sandbox): o código de origem desconhecida pode rodar, mas é mantido isolado dentro de uma caixa de areia, onde pode rodar em segurança sem causar qualquer dano ao "mundo real", que é o ambiente Java como um todo.

Quando um applet, ou outro código de origem desconhecida está rodando dentro da caixa de areia, ele fica submetido a diversas restrições sobre o que pode fazer. A mais óbvia dessas restrições é que ele não tem acesso de nenhum tipo ao sistema de arquivos local. Existem ainda várias outras restrições à caixa de areia. Na verdade, existe uma classe, chamada SecurityManager, especialmente para cuidar da implementação dessas restrições. Para assegurar o funcionamento do modelo de segurança, todas as classes do núcleo Java que executam operações de risco, como acesso ao sistema de arquivos, primeiro pedem permissão ao SecurityManager atualmente instalado. Se a chamada está sendo feita, direta ou indiretamente, por código de origem desconhecida, o gerenciador de segurança lança uma exceção, impedindo a operação.

Page 23: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

A tecnologia java e configuração do ambiente

1-17

A versão Java 1.1, implementa um recurso adicional à questão da segurança: a assinatura digital. Anexando uma assinatura digital ao código Java, a origem desse código pode ser estabelecida de uma forma criptograficamente segura e impossível de falsificar.

Desta forma, o usuário pode definir que uma determinada pessoa ou organização merece sua confiança. A partir daí, o código que traz a assinatura digital dessa entidade merece confiança mesmo que seja carregado através da rede, podendo rodar sem as restrições do modelo de caixa de areia.

Porém, quando se trata de segurança, é preciso ser realista. Da mesma forma que nunca se pode garantir que um programa seja 100% livre de bugs, nenhuma linguagem ou ambiente pode ter a garantia de ser 100% seguro. Dentro desses limites, Java com certeza oferece um bom nível de segurança para a maioria das aplicações práticas. Java antecipa e se defende contra a maioria das técnicas que têm sido usadas para fazer com que software tenha comportamento malicioso.

A segurança de Java foi intensamente testada por experts em segurança e também por hackers. Desta forma, foi possível sanar alguns furos de segurança encontrados nas primeiras versões de Java. É igualmente razoável esperar que quaisquer furos que venham a ser descobertos no futuro sejam sanados com a mesma rapidez.

Page 24: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

A tecnologia java e configuração do ambiente

1-18

O Just in Time Compiler - JIT

• Traduzem bytecodes Java para instruções nativas da máquina.

• Evitam a reinterpretação de blocos de código Java.

• Úteis se o mesmo bloco de código é executado mais de uma vez.

• Otimizam a execução de blocos de código repetitivos, como laços (for/while).

A JVM transforma os bytecodes Java em instruções nativa de máquina. Se um bloco de código é executado diversas vezes, a JVM tem o trabalho reinterpretar este mesmo bloco de código toda vez que o fluxo de execução o atingir.

Mas porque interpretar um bloco de código que não muda e já foi uma vez interpretado?

Uma nova técnica, conhecida como compilação sob demanda (Just-in-Time Compilation ou JIT Compilation), foi então desenvolvida para contornar este tipo de situação. Compiladores JIT, quando encontram um bloco de bytecodes Java pela primeira vez, o traduzem de maneira definitiva para instruções nativas de máquina.

Se o mesmo bloco é executado novamente, não há porque novamente interpretá-lo: as instruções nativas de máquina resultado da compilação Just-in-Time assumem o controle da execução, dispensando a necessidade de interpretação. Compiladores JIT aumentam o desempenho de programas Java, fazendo-os rodar mais rapidamente, uma vez que dispensam a necessidade de traduções sucessivas e “inúteis” de um mesmo bloco de bytecodes Java.

Os ganhos de desempenho são mais significativos quando da otimização de laços e funções recursivas, em que um mesmo bloco de código é exaustivamente repetido.

Page 25: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

A tecnologia java e configuração do ambiente

1-19

O Java Standard Development Kit – J2SDK

Abaixo temos uma figura que mostra toda a plataforma java de desenvolvimento. Observe que existem muitas tecnologias presentes nesta plataforma. Você não precisa saber todas elas para trabalhar com java. Colocamos esta figura de forma que você possa ver algumas importantes, as quais listamos abaixo:

• [ javac ] – Compilador Java, traduz programas Java para bytecodes

• [ java ] – Interpretador de bytecodes, para executar programas java

• [ appletviewer ] – Visualizador de applets, lê uma página HTML, carrega o applet referenciado pela página e o executa, mostrando em sua própria tela a entrada e saída do applet

• [ javadoc ] – Gerador de documentação, ferramenta que gera automaticamente documentação em HTML a partir dos comentários do código fonte Java

• [ jar ] – Empacotador de aplicações java, para a geração e manutenção de archives (jar). O formato de arquivos JAR possibilita o agrupamento de múltiplos arquivos em um único, que recebe o nome de Java Archive (ou .jar). Desta forma, um único arquivo .jar tipicamente contém vários binários Java (arquivos .class) e arquivos auxiliares de recursos utilizados pelo applet ou application Java

• [ javap ] – Disassembler, ferramenta recebe como entrada um binário Java (arquivo .class) e fornece como saída uma lista de comandos assembly da máquina virtual Java referentes ao binário analisado, ou uma lista de protótipos de classes encontradas no binário

• [ Swing ] – Framework para criação de interfaces dráficas

• [ Java Web Start ] – Tecnologia para distribuição de software

• [ JDBC ] – Framework para conexão com banco de dados

Page 26: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

A tecnologia java e configuração do ambiente

1-20

Arquitetura da tecnologia java

Na figura abaixo você tem listadas as tecnologias que fazem parte da versão 5.0 do Java. Estas tecnologias são parte do JRE (Java Runtime Environment) e do JDK ( Java Development Kit).

Figura 1-5: Estrutura do JDK e JRE

Page 27: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

A tecnologia java e configuração do ambiente

1-21

Figura 1-6: Relação dos grupos de tecnologias

Page 28: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

A tecnologia java e configuração do ambiente

1-22

Configurando o ambiente

Para trabalhar com a linguagem java na sua máquina é preciso configurar algumas coisas antes de escrever o promeiro programa. Estas configurações não são necessárias na máquina do usuário que irá rodar a sua aplicação, sendo configurações somente para a máquina do desenvolvedor. Você precisará adicionar as seguintes variáveis de ambiente ao sistema operacional que estiver utilizando:

1) JAVA_HOME - local onde foi instalado o java na sua máquina. Esta variável é utilizada por programas para localizar a máquina virtual java e o compilador

2) CLASSPATH – esta variável contém o caminho onde estão as

classes/bibliotecas java que o programa irá utilizar. Se você baixar algum pacote jar da internet com classes que desejar utilizar, será necessário colocar o caminho deste pacote nesta variável para que as classes do mesmo sejam localizadas no momento da compilação

3) PATH – esta variável é importante estar configurada para poder rodar os

programas que estão localizados dentro do diretório bin da sua instalação do java

Versão para windows: JAVA_HOME=C:\jdk1.5 CLASSPATH=%JAVA_HOME%\lib\tools.jar PATH=%JAVA_HOME%\BIN;%PATH%

Codigo 1-1: Configuração das variáveis de ambiente para windows

Versão para linux: JAVA_HOME=/jdk1.5 CLASSPATH=$JAVA_HOME/lib/tools.jar PATH=$JAVA_HOME/bin;$PATH

Codigo 1-2: Configuração das variáveis de ambiente para linux

Page 29: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

A tecnologia java e configuração do ambiente

1-23

API’s da linguagem

Java possui um conjuntomuito grande classes para serem utilizadas no desenvolvimento de palicações. Estas classes estão organizadas em pacotes que fazem parte do JDK. Abaixo você tem alguns dos principais pacotes que serão utilizados para o desenvolviemtno de aplicações. Para ter uma visão do todo basta acessar a documentação do JDK através de um browser. Siga o seguinte link para isto:

http://java.sun.com/j2se/1.5.0/docs/api/ java.applet Fornece as classes necessárias para a criação de um applet e

para a comunicação que posteriormente se estabelece entre o applet e o contexto em que executa.

java.awt Contém todas as classes para a criação de interfaces gráficas do usuário e controle de imagens.

java.beans Contém as classes relacionadas aos desenvolvimento de Java Beans.

java.io Permite entrada e saída através de data streams, serialization e sistema de arquivos.

java.lang Classes relacionadas ao próprio projeto da linguagem Java, referindo-se à manipulação e conversão de tipos, strings, threads e ambiente de execução.

java.math Classes utilizadas para aritmética de inteiros de precisão arbitrária (BigInteger) e para a aritmética de decimais de precisão arbitrária (BigDecimal)

java.net Classes contendo facilidades de comunicação em rede (manipulação sockets, resolução de nomes, estabelecimento de canais de comunicação).

java.security Classes e interfaces relacionadas às questões de segurança.

java.sql Classes que permitem interface com o banco de dados (JDBC)

java.text Classes e interfaces para manipulação de texto, datas, números e mensagens.

java.util Miscelânea de classes auxiliares: tratamento do tempo, gerador de números aleatórios, vetores de bits, internacionalização do aplicativo, manipulação de archives Java, etc.

javax.swing Conjunto de componentes visuais “peso leve” que, com o máximo grau de compatibilidade possível, funcionam da

Page 30: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

A tecnologia java e configuração do ambiente

1-24

mesma maneira em todas as plataformas.

Tabela 1-1: Pacotes mais comuns da API J2SDK

Page 31: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

A tecnologia java e configuração do ambiente

1-25

Espaço para anotações

Page 32: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Java Fundamentals

2-1

22.. TTiippooss ee OOppeerraaddoorreess

Page 33: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tipos e operadores

2-2

Objetivos

• Compreender as seguintes estruturas:

o Variáveis

o Tipos Primitivos

o Literais

• Compreender os tipos de dados primitivos:

o char

o boolean

o byte, short, int, long

o float, double

• Compreender os tipos de dados compostos

• Apreender conversões de tipos

• Conceituar expressões e operadores

• Definir precedência e associatividade entre estruturas

Page 34: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tipos e operadores

2-3

Variáveis

Java é uma linguagem fortemente tipada.

Isto significa que a utilização de qualquer variável deve ser compatível com a sua prévia definição.

Compete ao compilador da linguagem verificar, antes mesmo da execução do programa (isto é, de maneira estática), se há a referida compatibilidade entre definição e uso de uma variável.

Os contextos em que uma variável pode ser validamente empregada são determinados pelo seu tipo. O tipo determina a utilização: restringe as operações aplicáveis e concede sentido ao resultado de uma operação válida (semântica da operação). Seria contra-senso somarmos um tipo booleano com outro tipo booleano ou, ainda pior, multiplicarmos um booleano por um número fracionário.

Qual a resposta esperada para estas operações?

Não há resposta, porque a operação frente aos tipos carece de coerência. Ao definirmos um inteiro (ou um número real, ou um booleano, etc.), estamos a dizer quais operações são válidas quando aplicadas a este inteiro (real, booleano, etc.) e quais simplesmente carecem de sentido.

Decorrem do fato de Java ser fortemente tipada:

• Todas as variáveis em Java devem ter um tipo associado (a fim de que se possa avaliar futuramente se os empregos dados a esta variável são ou não corretos)

• A utilização de uma variável deve ser posterior à sua definição

• As conversões forçadas de tipo (casts) devem ser rigidamente controladas pela linguagem, tanto sob o aspecto estático (não se permitindo conversões entre tipos distintos, e autorizando tão somente a conversão entre tipos derivados), quanto sob o aspecto dinâmico (controle em tempo de execução das conversões de tipo efetuadas).

• Não se permitem conversões implícitas de tipo. Todas as conversões de tipo devem ocorrer de maneira expressa.

Page 35: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tipos e operadores

2-4

Tipos primitivos e tipos compostos

Tipos primitivos são aqueles tipos já embutidos na linguagem java e estudados no capítulo anterior, enquanto tipos compostos são todas as classes da linguagem java ou classes que você venha a criar.

Variáveis de tipos primitivos são tratadas de uma maneira bem diferente de variáveis de referências para objetos ( variáveis de tipos compostos). É bastante importante saber quais são estas diferenças e porque Java foi projetada desta forma.

Variáveis de tipos primitivos

Quando você declara uma variável de um tipo primitivo, Java aloca um pedaço de memória que é grande o suficiente para guardar valores do tipo primitivo declarado. Se você define uma variável de tipo primitivo como uma variável de instância, a variável é inicializada para 0 se for inteira, para false se for booleana e para '\0' se for caractere.

Variáveis de tipos primitivos armazenam o seu valor diretamente. Se você, por exemplo, declara uma variável do tipo int e atribui um valor 3 para esta variável, o valor é armazenado diretamente nos quatro bytes reservados para a variável.

Variáveis de referências para objetos (tipos compostos)

Quando você declara uma variável de referência, você também recebe um pedaço de memória, mas esta memória é grande o suficiente para armazenar apenas uma referência para o objeto. Talvez seja útil pensar em uma referência como um apontador para o objeto.

Como mencionado antes, declarar uma variável de referência não cria um objeto do tipo especificado. Conseqüentemente, uma variável de instância é inicializada para null a fim de indicar que ainda não recebeu referência para nenhum objeto ainda.

Page 36: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tipos e operadores

2-5

Use o operador de atribuição para fazer com que uma variável de referência se refira a uma instância de uma classe. A atribuição pode ser para um objeto existente ou para um objeto recém criado através do operador new.

Page 37: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tipos e operadores

2-6

Tipos Primitivos

Tipos primitivos são aqueles fornecidos diretamente pela linguagem, ou seja, tipos já embutidos na linguagem. São tipos atômicos, indivisíveis e sobre os quais a linguagem, de ante mão, já oferece operações pré-definidas. Exemplos de tipos primitivos são inteiros e booleanos. Para usá-los, basta associá-los a uma variável. A maior parte das linguagens permite ao programador criar tipos compostos. Tipos compostos procuram representar de maneira conjunta e unificada os vários atributos de uma entidade modelada. Um catálogo telefônico pode ser representado dentro de um programa como uma lista de Strings contendo nomes, outra contendo os endereços e, por fim, uma outra contendo os telefones.

Todas as informações necessárias à pesquisa ou à manipulação do catálogo estão presentes em tais listas. Mas esta definitivamente não é a melhor maneira de se representar um catálogo telefônico. Se perguntarmos a alguém o que é um catálogo, dificilmente ouviremos como resposta uma lista de nomes, endereços e telefones.

A resposta mais provável é uma lista de assinantes. Um assinante, por sua vez, é identificado pelo nome que possui ou endereço onde reside. Ao procurarmos descobrir o telefone de um assinante, pesquisaremos pelas chaves que o identificam: nome ou endereço. A representação estruturada da informação é, em si, informação relevante. Ao modelarmos um catálogo como uma lista de assinantes e identificarmos um assinante pelo seu nome ou endereço, estamos trazendo para dentro do programa não apenas informação contida em um catálogo, mas também a própria estrutura de um catálogo: informação sobre como a informação é organizada.

Os tipos compostos não são apenas armazéns de dados. A sua função principal não é conter o dado, pois para isto já temos tipos primitivos. O seu objetivo principal é organizar a informação. Aproximar a estrutura empregada na confecção do modelo da estrutura existente no mundo real modelado. Tornar a tarefa de programar mais intuitiva, permitindo uma relação direta entre o modelo e o objeto modelado. A representação do dado dentro do programa facilita a compreensão do próprio programa como modelo. Não basta fazer um programa (modelo) que funcione. É necessária tanto uma compreensão do mundo real através do programa, quanto uma compreensão do próprio programa como modelo do mundo real.

Tipos compostos são construídos tendo como blocos construtores tipos primitivos ou, de maneira recursiva, outros tipos compostos. Em última análise, os tipos primitivos são os únicos responsáveis pela construção dos tipos compostos. Um tipo composto nada mais é que um conjunto organizado de tipos primitivos. Tipos compostos serão vistos em capítulos posteriores.

Page 38: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tipos e operadores

2-7

Java possui oito tipos primitivos: boolean, char, byte, short, int, long, float e double. Cada um destes tipos será estudado de maneira mais detalhada nas seções seguintes. A tabela abaixo apresenta um resumo dos tipos primitivos encontrados na linguagem Java.

Cumpre observar que o tamanho do tipo em bytes e a sinalização fazem parte da especificação da linguagem.

Ou seja, um char em Java ocupará sempre 16 bits, um int 32 bits, um long 64 bits, e assim por diante, independente da plataforma em que o programa esteja sendo executado.

Page 39: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tipos e operadores

2-8

Tabela 2-1: Tipos primitivos e suas características.

Ao contrário do que acontece com outras linguagens de programação, as características dos tipos de dados listados acima idependem da plataforma em que o programa deverá ser executado.

Dessa forma, os tipos de dados primitivos são realmente únicos e garantem a capacidade de intercâmbio de informações entre diversos tipos de

Tipo Contém Default Tamanho Faixa de valores

boolean true ou false false 1 bit Pode assumir o valor true ou o valor false

char caracter Unicode \u0000 16 bits Serve para a armazenagem de dados alfanuméricos. Também pode ser usado como um dado inteiro com valores na faixa

entre: 0 e 65535 (\u0000 a \uFFFF)

byte inteiro com sinal 0 8 bits Inteiro de 8 bits em notação de complemento de dois. Pode assumir valores entre:

-27 a 27-1

short inteiro com sinal 0 16 bits Inteiro de 16 bits em notação de complemento de dois. Os valores possívels cobrem a

faixa entre: -215 a 215-1

int inteiro com sinal 0 32 bits Inteiro de 32 bits em notação de complemento de dois. Pode

assumir valores entre: -231 a 231-1

long inteiro com sinal 0 64 bits Inteiro de 64 bits em notação de complemento de dois. Pode

assumir valores entre: -263 a 263-1

float ponto flutuante 0.0 32 bits Representa números em notação de ponto flutuante. A sua

representação é exponencial, sendo alguns bits utilizados para base e outros para o

expoente.

double ponto flutuante 0.0 64 bits Representa números em notação de ponto flutuante. A sua

representação é exponencial, sendo alguns bits utilizados para base e outros para o

expoente.

Page 40: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tipos e operadores

2-9

computadores, aliviando o programador da preocupação e da árdua tarefa de converter dados em formatos apropriados para a portagem.

Page 41: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tipos e operadores

2-10

Declarando um tipo primitivo

São oito os tipos primitivos de Java: boolean, char, byte, short, int, long, float e double. Quarenta e quatro são os operadores que podem ser utilizados na manipulação destes tipos primitivos.

Declarar e inicializar uma variável de um tipo primitivo é extremamente fácil. Basta, a exemplo da seguinte linha de código, associar ao identificador escolhido pelo usuário para a variável um dos tipos acima, atribuindo, logo em seguida, um literal para esta variável.

Código 2-1: Literais primitivos.

O que é uma literal?

Uma resposta simples seria: constantes para cada um dos tipos primitivos de uma linguagem. Na verdade, literais são construções sintáticas fornecidas pela linguagem para exprimir valores constantes para cada um dos tipos primitivos. Tais construções determinam como devem ser escritos um caractere, um inteiro, um valor booleano, etc.

A maior parte das linguagens permite que haja mais de uma forma de se escrever um valor inteiro, ora transcrevendo o valor inteiro em uma base de numeração Octal, ora transcrevendo-o em uma base Decimal, ora em uma base Hexadecimal.

O mesmo ocorre para os números em ponto flutuantes: a maior parte das linguagens permite que ora sejam escritos em notação convencional (parte inteira + caractere separador + parte fracionária), ora em notação científica (número fracionário + expoente em potência decimal).

Conjunto de Caracteres Unicode

Page 42: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tipos e operadores

2-11

Os programas Java são escritos usando o conjunto de caracteres Unicode. Ao contrário da codificação de 7 bits ASCII, que é útil somente para a língua inglesa, e codificações de 8 bits, tais como ISO Latin-1, que é útil somente para a maior parte das línguas da Europa Ocidental, a codificação Unicode, de 16 bits, consegue representar praticamente todas as linguagens de uso freqüente no planeta. Entretanto, poucos editores de texto suportam caracteres Unicode, e na prática, a maior parte dos programas são escritos em ASCII.

Os caracteres Unicode, de 16 bits, são usualmente escritos em arquivos usando uma codificação conhecida como UTF-8, que converte os caracteres de 16 bits em uma seqüência de bytes. O formato é projetado de forma que um texto escrito em ASCII ou em ISO Latin-1 são seqüências de bytes UTF-8 válidas.

Desta forma, você pode simplesmente escrever programas em ASCII e eles se comportarão, graças às características de projeto da codificação UTF-8, como textos Unicode válidos.

Se você quiser inserir um caracter Unicode dentro de um programa Java escrito em ASCII, basta usar a seqüência de escape especial para caracteres Unicode \uxxxx. Isto é, uma contrabarra mais a letra u em minúscula seguida de quatro caracteres hexadecimais.

A seqüência de escape \u0020 representa caracter de espaço, e a seqüência \u3c00 é o caracter π. Você pode usar caracteres Unicode em qualquer lugar em um programa Java, incluindo comentários e nome de variáveis.

Podemos encontrar a tabela unicode no seguinte endereço:

http://www.unicode.org

Page 43: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tipos e operadores

2-12

Tipo caracter – char

O tipo char representa caracteres Unicode. É motivo de surpresa para experientes programadores descobrir que valores char em Java possuem 16 bits de extensão.

Na prática, no entanto, isto fica completamente transparente.Um literal caracter em Java sempre vem entre aspas simples.

Código 2-2: Declarando um tipo char

Você pode, é claro, usar qualquer caracter Unicode como um literal caracter, sendo necessário tão somente o emprego de seqüências de escape \uxxxx Unicode.

Java suporta também várias outras seqüências de escape que facilitam a representação de caracteres ASCII não visíveis, tais como nova linha ou backspace, e permitem o escape na construção de literais contendo caracteres de pontuação com significado especial, tais como aspas duplas ( “ ) e aspas simples ( ‘ ).

Por exemplo:

Código 2-3: Exemplos de char especiais

char a = ′A′, espaco = ′ ′;

char tab = ′\t′, apostrofe = ′\′′, nulo = ′′;

char unicode = ′\u05D0′;

Page 44: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tipos e operadores

2-13

A tabela abaixo mostra os caracteres de escape que podem ser utilizados na construção de um literal caracter.

Seqüência de escape

Valor do caracter

\b backspace

\t tabulação horizontal

\n nova linha

\f alimentação de formulário

\r retorno de carro

\” aspas duplas

\’ aspas simples

\\ contrabarra

\uxxxx Caracter Unicode com codificação xxxx, onde xxxx são quatro dígitos hexadecimais.

Tabela 2-2: Caracteres de escape do tipo char

Estas seqüências de escape podem também ser usadas em literais para Strings.

Valores do tipo char não podem ser convertidos para e a partir de tipos inteiros. Ao contrário de byte, short, int e long, o tipo char é um tipo não sinalizado (unsigned).

A classe Character vários métodos estáticos (static methods) para trabalhar com caracteres, incluindo isLowerCase() e toUpperCase().

Page 45: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tipos e operadores

2-14

Tipo booleano – boolean

O tipo boolean procura representar predicados. Há somente dois valores possíveis para este tipo, representando os dois estados booleanos: ligado ou desligado, sim ou não, verdadeiro ou falso.

Java reserva as palavras true e false para representar estes dois valores booleanos.

Programadores C e C++ devem ter notar que Java é bem restritiva quanto à utilização do tipo booleano: valores booleanos não podem ser diretamente convertidos para outros tipos de dados, nem estes podem ser convertidos para booleanos.

Em especial, o valor booleano não é um tipo inteiro (onde false é representado por 0 e true por qualquer valor diferente de 0), e valores inteiros não podem ser usados no lugar de um valor booleano.

Os exemplos abaixo mostram a utilização incorreta de valores booleanos. No primeiro exemplo, um booleano é esperado e um inteiro é fornecido.

Errado Correto int i = 10; while(i) { ... i--; }

int i = 10; while(i!=0) { ... i--; }

Tabela 2-3: Utilização do tipo boolean em C++ e Java

Não há (como ocorre com C e C++) conversão, implícita ou forçada, entre booleanos e inteiros (ou outro tipo primitivo qualquer).

Page 46: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tipos e operadores

2-15

Tipos inteiros - byte, short, int e long

Os tipos inteiros em Java são byte, short, int e long. Os tipos inteiros diferem exclusivamente no número de bits usados para a representação do número e, portanto, na extensão da faixa de números que conseguem representar. Todos os tipos inteiros são sinalizados.

Não existe em Java nada equivalente à especificação unsigned de C ou C++.

Literais inteiros para cada um destes tipos são construídos da maneira esperada: uma seqüência de números decimais. Qualquer literal inteiro pode ser precedido por um operador unário menos, a fim de indicar um número negativo.

Alguns literais inteiros:

Código 2-4: Literais inteiros int

Literais inteiros podem ser expressos também em notação octal ou hexadecimal. Um literal que começa com 0x ou 0X é interpretado como um número hexadecimal, valendo-se das letras A a F (ou a a f) para os dígitos restantes requeridos em números de base 16.

Literais inteiros que têm um dígito 0 em seu início são interpretados como números octais (base 8) e, portanto, entre os dígitos subseqüentes não podem figurar os algarismos 8 e 9. Java não permite que literais inteiros sejam expressos em notação binária (base 2). Literais inteiros octais e decimais válidos:

Código 2-5: Literais inteiros int em hexa e octal

Literais inteiros exprimem valores de 32 bits, a menos que terminem com o caracter L ou l, indicando, neste caso, serem tais literais valores de 64 bits.

0 1 -123 -4200

0xff // decimal 255 expresso em hexa 0377 // mesmo número expresso em octa

1234 // um valor int 1234L // um valor long 0xffL // outro valor long

Page 47: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tipos e operadores

2-16

Código 2-6: Literais inteiros int e long

A aritmética inteira em Java é modular. Não há transbordo ou estouro na manipulação de números inteiros.

Ao contrário, ao exceder a faixa de um determinado tipo inteiro, em uma das extremidades, o resultado da operação avança de maneira circular sobre a extremidade oposta.

Por exemplo:

Código 2-7: Exemplo de expressão byte com aritmética circular

Nem o compilador Java, nem a JVM avisará quando ocorrer transbordo em aritmética inteira. Desta maneira, ao manipular inteiros, você deve ter certeza que o tipo que está usando é grande o suficiente para os propósitos que tem em mente. Que a faixa de números oferecida pelo tipo é larga o suficiente para as operações pretendidas.

Divisões inteiras por zero e operações módulo zero não são aceitas e lançam a exceção ArithmeticException.

Cada tipo inteiro tem uma classe invólucro correspondente (wrapper classes): Byte, Short, Integer e Long. Cada uma dessas classes define as constantes MIN_VALUE e MAX_VALUE que descrevem as extremidades da faixa de números suportada pelo tipo.

Estas classes também definem vários métodos estáticos extremamente úteis, tais como Byte.parseByte() e Integer.parseInt(), empregados na conversão de strings para inteiros.

byte b1 = 127, b2 = 1; byte sum = b1 + b2; // sum = -128, que é o menor byte

Page 48: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tipos e operadores

2-17

Tipos de ponto flutuante - float e double

Números reais são representados em Java com os tipos float e double. Como mostrado anteriormente, o tipo float representa um valor de ponto flutuante, de 32 bits, de precisão simples, enquanto o tipo double representa um valor de ponto flutuante de 64 bits, de precisão dupla. Ambos os tipos seguem o padrão IEEE 754-1985, que especifica tanto o formato dos números quanto o comportamento da aritmética com estes números.

Literais de ponto flutuante podem ser representados em Java como uma seqüência opcional de dígitos decimais seguido por um ponto e outra seqüência de dígitos decimais.

Alguns exemplos:

Código 2-8: Literais float e double

Literais de ponto flutuante também podem ser representados através de notação científica, na qual um número é seguido pela letra e ou E (assinalando o expoente) e por um outro número. Este segundo número representa a potência de dez pela qual o primeiro número é multiplicado.

Por exemplo:

Código 2-9: Literais float em notação científica

Números de ponto flutuante são double por default. Para representar um literal de ponto flutuante float em um programa, basta acrescentar o caracter f ou F no final do número.

Código 2-10: Literais float e double em notação científica

Literais de ponto flutuante não podem ser representados em notação hexadecimal ou octal. A maior parte dos números reais, pela sua natureza, não

123.45f // float 0.0 // double .02 // double

1.2345E02 // 1.2345 x 102 ou 123.45 1e-6 // 1 x 10-6 ou 0.000001 6.02e23 // No. de Avogrado 6.02 x 1023

double d = 6.02e23; float f = 6.02e23f;

Page 49: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tipos e operadores

2-18

pode ser representada exatamente em um número finito de bits. Portanto, é importante se lembrar que os valores double e float são apenas aproximações dos números que eles procuram efetivamente representar.

Um float é uma aproximação de 32 bits, o que resulta em pelo menos 6 dígitos decimais significativos, e o double é uma aproximação de 64 bits, o que, por sua vez, resulta em pelo menos 15 dígitos decimais significativos. Na prática, estes tipos são suficientes para a maior parte das computações de ponto flutuante.

Page 50: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tipos e operadores

2-19

Tipo composto – String

Além dos tipos primitivos caracter, booleano, inteiro e real, Java também possui um tipo de dado próprio para trabalhar com seqüências de texto (Strings).

O tipo String, no entanto, não é um tipo primitivo da linguagem. Devido ao uso extremamente freqüente de Strings em um programa, Java permite uma sintaxe especial para a representação de literais Strings. Um literal String consiste de uma porção arbitrária de texto delimitada por aspas duplas.

Por exemplo:

Código 2-11: Literias Strings

Literais Strings podem conter qualquer uma das seqüências de escapes permitidas para um valor char. Utilize a seqüência \" para incluir aspas duplas dentro de um literal String. String e literais Strings serão discutidos com mais detalhes a seguir.

"Hello, World" "Isto é uma string \n"

Page 51: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tipos e operadores

2-20

Conversões de tipos – casting

Java permite conversão entre valores inteiros e valores reais. Além disto, por corresponder todo caracter a um número na codificação Unicode, o tipo char pode ser convertido para e a partir de um tipo inteiro ou de ponto flutuante. De fato, o tipo boolean é o único tipo que não pode ser convertido para ou a partir de um outro tipo primitivo em Java. Há dois tipos de conversão.

Uma conversão de ampliação (widening conversion) ocorre quando um valor de um tipo é convertido para outro tipo mais amplo um tipo que possui mais bits de representação e, portanto, uma faixa mais ampla de valores representados.

Uma conversão de redução (narrowing conversion) ocorre quando um valor é convertido para outro que possui menos bits de representação. Java automaticamente se encarrega das conversões de ampliação quando, por exemplo, uma variável double recebe um valor int, ou um literal char é atribuído a uma variável int.

Conversões de redução são um problema a parte, e nem sempre são seguras. É razoável, por exemplo, converter o valor inteiro (int) 13 para um byte, mas não o é fazer a mesma conversão para o valor 13000, pois o tipo byte suporta somente valores entre –128 e 127. A informação pode ser perdida em conversões de redução e o compilador Java sempre reclama quando há uma tentativa de efetuar uma conversão de redução, ainda que o valor sendo convertido se situe entre os valores aceitos pela faixa mais estreita do novo tipo.

Código 2-12: Atribuição de valor inteiro int não permitida para byte

A única exceção a esta regra é que você pode atribuir um literal inteiro (portanto, um valor int) para uma variável byte e short, se o literal pertencer à faixa de representação desta variável. Se você precisa de conversões de redução e está confiante que o pode fazer sem perda de informação ou precisão, você pode forçar Java a executar a conversão usando uma construção da linguagem conhecida como cast (conversão explícita).

A conversão explícita é feita colocando-se o nome do tipo pretendido entre parênteses antes da variável a ser convertida.

Por exemplo:

int i = 13; byte b = i; // Erro em tempo de compilação.

int i = 13; byte b = (byte) i; i = (int) 13.456;

Page 52: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tipos e operadores

2-21

Código 2-13: Conversão forçada de tipos primitivos

Casting de tipos primitivos são mais freqüentes em conversões de números reais para inteiros. Quando isto ocorre, a parte fracional do número real é simplesmente truncada (o valor de ponto flutuante é arredondado para zero e não para o inteiro mais próximo). Os métodos Math.round(), Math.floor() e Math.ceil() permitem outros tipos de arredondamento.

Código 2-14: Atribuição de valores implícitos e expressos

O tipo char funciona como um tipo inteiro a maior parte das vezes, podendo, portanto, ser usado em qualquer lugar em que se espere um int ou long.

Lembre-se, no entanto, que o tipo char é não sinalizado e se comporta de maneira diferente do tipo short, embora ambos possuam 16 bits.

short s = (short) 0xffff; char c = '\uffff'; int i1 = s; int i2 = c;

Page 53: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tipos e operadores

2-22

Tipos de referência

Além dos oito tipos primitivos, Java define duas outras categorias de tipos: classes e vetores. Programas em Java são construídos através de definições de classes; cada classe define um novo tipo de dado que pode ser manipulado por programas Java.

Um programa pode, por exemplo, definir uma classe chamada Ponto e usá-la para armazenar coordenadas (x,y) de um sistema cartesiano de coordenadas. Com isto, Ponto passa a ser um novo tipo de dado em um programa.

Um tipo vetor representa uma lista de valores de um determinado tipo. int é um tipo de dado, e um vetor de valores do tipo int é outro tipo de dado, escrito em Java como int[]. Um vetor de objetos do tipo Ponto também é um tipo, escrito como Ponto[]. E um vetor de vetores de Ponto é também um outro tipo, escrito em Java como Ponto[][].

Como você pode ver, há um número infinito de tipos de dados de classes e vetores possíveis. Basta o programador defini-los. Estes tipos são conhecidos coletivamente como tipos de referência.

A razão para este nome ficará clara logo a seguir. Por enquanto, é importante compreender apenas que classes e vetores são tipos de dados diferentes dos tipos primitivos. Tipos de dados de classes e vetores são conhecidos como tipos compostos. Um tipo de dado primitivo guarda somente um único valor.

Classes e vetores são tipos agregados que contém vários valores. O tipo Ponto, por exemplo, armazena dois valores double representando as coordenadas x e y do ponto. Classes e vetores serão retomados logo adiante.

Código 2-15: Tipos de referências: arrays e Strings

int[] vet = {1,2,3};

String str = new String(“Java”);

Page 54: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tipos e operadores

2-23

Expressões e operadores

Até o presente momento, aprendemos sobre os tipos primitivos que os programas Java são capazes de manipular e vimos como construir literais para cada um destes tipos. Utilizamos também variáveis, nomes simbólicos que representam e armazenam um valor.

Literais e variáveis são importantes tokens com os quais programas são construídos em Java.

Expressões são o próximo nível de estrutura de um programa Java. O interpretador Java (JVM) avalia uma expressão para determinar o seu resultado. As expressões mais simples são chamadas expressões primárias e consistem de apenas um literal ou uma variável.

São exemplos de expressões primárias:

Código 2-16: Expressões primárias

Quando o interpretador Java avalia uma expressão literal, o resultado da avaliação é o próprio literal. Quando o interpretador avalia uma expressão contendo uma variável, o resultado da avaliação é o resultado armazenado nesta variável.

Expressões primárias não são muito interessantes. Expressões mais complexas são construídas utilizando operadores para combinar expressões primárias. Por exemplo, a seguinte expressão usa o operador de atribuição ( = ) para combinar duas expressões primárias – uma variável e um literal de ponto flutuante – em

uma expressão de atribuição.

Código 2-17: Expressão de atribuição

Mas operadores não são usados apenas com expressões primárias; eles também podem ser usados com expressões de qualquer nível de complexidade. As seguintes construções são, portanto, expressões válidas.

1.7 'A' true sum

sum = 1.7

sum = 1 + 2 + 3 * 1.2 + (4 + 8) / 3.0; sum = (sum / Math.sqrt(3.0 * 1.234) ); sum = (int) (sum + 33);

Page 55: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tipos e operadores

2-24

Código 2-18: Expressões válidas e combinadas

Page 56: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tipos e operadores

2-25

Sumário de operadores

Os tipos de expressões que você pode escrever em uma linguagem de programação dependem completamente do conjunto de operadores que a linguagem disponibiliza. A tabela abaixo apresenta síntese dos operadores disponíveis em Java. A colunas P e A desta tabela indicam, respectivamente, a precedência e a associatividade de cada grupo de operadores correlatos. Neste curso veremos alguns operadores listados na tabela abaixo, os demais serão vistos a medida do estudo da linguagem.

Operadores Tipo de operando

Operação executada

. objeto, membro acesso a membro do objeto

[] vetor, inteiro acesso a elemento do vetor

( args ) método, lista de args

invocação do método

++, -- variável pós incremento, pós decremento

++, -- variável pré incremento, pré decremento

+, - número mais unário, menos unário

~ inteiro complemento (NOT bit a bit)

! booleano NOT booleano

new classe, lista de args criação de objetos

(type) tipo, qualquer coisa

cast (conversão explícita de tipo)

*, /, % número, número multiplicação, divisão e resto

+, - número, número adição e subtração

+ string, qqr coisa concatenação de strings

<, <= número, número menor que, menor que ou igual

>, >= número, número maior que, maior que ou igual

instanceof referência, tipo comparação de tipos

== primitivo, primitivo igual (o mesmo valor)

!= primitivo, primitivo não igual (valores diferentes)

Page 57: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tipos e operadores

2-26

== referência, referência

igual (o mesmo objeto)

!= referência, referência

não igual (objetos diferentes)

& inteiro, inteiro AND bit a bit

& booleano, booleano

AND booleano

^ inteiro, inteiro XOR bit a bit

^ booleano, booleano

XOR booleano

| inteiro, inteiro OR bit a bit

| booleano, booleano

OR booleano

&& booleano, booleano

AND booleano com curto circuito

|| booleano, booleano

OR booleano com curto circuito

? : booleano, qqr coisa, qqr coisa

operador ternário condicional

= variável, qqr coisa atribuição

*=, /=, %=, +=, -=, <<=, >>=, >>>=, &=, ^=,

|=

variável, qqr coisa atribuição geminada com operação

Tabela 2-4:Sumário de Operadores

Page 58: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tipos e operadores

2-27

Precedência

A precedência indica a ordem na qual as operações são executadas.

Considere a seguinte expressão:

Código 2-19: Expressão com precedência

O operador de multiplicação tem prioridade mais alta que o operador de adição, logo a é somado ao resultado da multiplicação de b e c.

A precedência de um operador pode ser pensada como uma medida de quão firmemente está ligado o operador aos seus operandos.

Quanto maior a precedência de um operador, mais firmemente ele está ligado aos seus operandos.

A precedência default de um operador pode ser afastada através do uso de parêntesis, de forma a explicitar a ordem exata das operações. A expressão anterior pode ser rescrita como se segue, determinando explicitamente que a adição deve ocorrer aqui antes da multiplicação.

Código 2-20: Expressão utilizando parêntesis

A precedência default dos operadores de Java foi escolhida procurando torná-la compatível com C. Os projetistas de C, ao determinar a precedência default de cada um dos operadores, tiveram em mente a maneira mais fácil e direta de se escrever expressões sem a necessidade do uso de parêntesis.

Há apenas algumas expressões em Java em que se faz necessária a presença de parêntesis.

a + b * c

(a + b) * c

Page 59: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tipos e operadores

2-28

Associatividade

Quando uma expressão contém vários operadores que têm a mesma precedência, a associatividade dos operadores indicarão a ordem na qual as operações serão executadas. A maior parte dos operadores tem associatividade da esquerda para direita, o que significa que as operações são feitas da esquerda para a direita. Operadores unários e de atribuição possuem, entretanto, associatividade da direita para esquerda.

Os operadores aditivos possuem associatividade da esquerda para direita, sendo a expressão a+b-c avaliada da esquerda para direita: (a+b)-c. Operadores unários e de atribuição são avaliados da direita para a esquerda.

Considere a seguinte expressão:

Código 2-21: Associatividade com incremento

O valor das variáveis seria:

Código 2-22: Resultado depois da execução do código acima

A associatividade, assim como a precedência, estabelece a ordem default de avaliação para uma expressão. Esta ordem default pode ser afetada com o uso de parênteses. Entretanto, a escolha da precedência e da associatividade conduz a uma sintaxe mais natural, e raramente você precisará alterá-la.

int a = 5; int b = 4; int c = a++ + b++

a = 6 b = 5 c = 9

Page 60: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tipos e operadores

2-29

Tipos de operadores: unários e binários

A quarta coluna da tabela acima especifica o número e o tipo dos operandos esperados para cada operador. Alguns operadores atuam somente sobre um único operando; são chamados operadores unários.

A maior parte dos operadores, no entanto, são operadores binários e atuam sobre dois operandos.

Exemplo operador unário: i++ é igual a i = i + 1

Exemplo operador binário: res = x + y

Page 61: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tipos e operadores

2-30

Espaço para anotações

Page 62: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tipos e operadores

2-31

Page 63: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Java Fundamentals

3-1

33.. CCrriiaannddoo ccllaasssseess ee oobbjjeettooss

Page 64: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Criando classes e objetos

3-2

Objetivos

• Definir classes, atributos e operações

• Trabalhar com pacotes

• Conhecer padrões para codificação

• Aplicar visibilidade a classes, atributos e operações

• Comentar os códigos fonte

• Gerar documentação do código fonte

• Estudar o escopo das variáveis

Page 65: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Criando classes e objetos

3-3

Classes e Objetos

Uma classe é um gabarito utilizado para criar múltiplos objetos. Uma classe encapsula todos os dados e comportamentos que definem um objeto. Quando você pede ao interpretador Java para criar ou instanciar um objeto, Java usa a definição de classes como gabarito para a criação de novos objetos.

Uma classe pode conter atributos que são atribuídos a todos os novos objetos desta classe. Atributos são informações ou dados que descrevem, categorizam ou quantificam um objeto. Cada novo objeto de uma dada classe terá seu próprio conjunto de atributos de classe. Um objeto da classe Cliente, por exemplo, terá um nome, um endereço e um número telefônico como atributos.

Dados armazenados em um objeto podem ser tanto primitivos, tais como inteiros ou caracteres, ou referências para outros objetos.

Uma classe pode conter também métodos ou funções que especifiquem o comportamento ou ações que a classe consegue realizar. A classe Cliente, por exemplo, pode alugar um carro, efetuar um pagamento ou alterar o seu endereço.

Java utiliza pacotes para agrupar classes que estão logicamente relacionadas. Pacotes consistem de classes fisicamente localizadas em um mesmo diretório. Pacotes também são usados para controlar o acesso de classes definidas fora do pacote.

Page 66: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Criando classes e objetos

3-4

Criando uma classe

O bloco contendo a definição de uma classe começa pela palavra reservada class. No código abaixo temos a criação de uma classe para reprensentar um Produto.

Código 3-1: Declaração da classe Produto

Uma classe – o bloco de construção básico para uma linguagem orientada a objetos – é uma coleção de dados e de métodos que manipulam estes dados. A classe é um modelo abstrato, a partir do qual serão criadas instâncias desta classe, contendo os dados e os métodos nela definidos.

Observe que a definição da classe acima é muito simples e a mesma é feita através da palavra reservada class. O par de chaves utilizado serve para delimitar o corpo da classe, ou seja, onde iremos colocar as operações e atributos da mesma. Veremos mais adiante como colocar os atributos e operações

Os dados referentes a uma classe são armazenados em variáveis e as operações efetuadas sobre estes dados são implementadas através de métodos.

Seguindo os passos contidos nesta lição você conseguirá criar e executar sua primeira Java Application. Para isto vamos adicionar um método especial nesta classe que nos permitirá executar a máquina virtual e executar algum código.

Tomaremos como exemplo, para a primeira Java Application, o consagrado “Hello World”. Este programa, bastante simples, imprime na tela do computador a mensagem “Hello World”. Usando um editor de texto, crie um arquivo de nome HelloWorld.java contendo as seguintes linhas.

Código 3-2: Exemplo de HelloWorld Java

class Produto {

}

class HelloWorld { public static void main( String[] args ) { System.out.println( "Hello World!" ); } }

Page 67: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Criando classes e objetos

3-5

O arquivo fonte pode ser compilado através de seu IDE ou usando o compilador javac através de linha de comando como mostrado abaixo

Código 3-3: Compilando uma classe Java

Obtendo êxito na compilação, o arquivo HelloWorld.class, contendo os bytecodes Java, será criado pelo compilador no mesmo diretório em que se encontra o arquivo fonte.

Caso o compilador tenha reportado alguma falha, verifique se não digitou algo incorretamente, prestando atenção para o uso de maiúsculas e minúsculas. Certifique-se também de ter dado ao arquivo o nome correto. Execute a aplicação Java usando a máquina virtual fornecida pelo JDK (java):

Código 3-4: Executando uma classe Java sem pacote

Você verá a mensagem “Hello World!” escrita na tela de seu computador.

C:\> javac HelloWorld.java

C:\>java HelloWorld Hello World!

Page 68: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Criando classes e objetos

3-6

Padrões

A linguagem java segue padrões para escrita de código especificados pela Sun, empresa criadora da linguagem java. Desenvolvedores devem procurar seguir estes padrões, uma vez que todo código de APIs que existem seguem este padrão para facilitar o endendimento dos mesmos bem como a leitura destes códigos.

O compilador Java (javac), bem como todas as demais ferramentas do JDK, diferenciam maiúsculas de minúsculas. Este recurso é chamado de case-sensitive. Portanto, bastante cuidado ao grafar o nome de classes, métodos, variáveis e pacotes. Erros comuns decorrem muitas das vezes de problemas envolvendo grafia, em que um nome, por exemplo, é definido em maiúsculas, e depois, logo adiante, é utilizado em minúsculas. O compilador simplesmente alegará que tal variável, método, classe ou pacote não foi definido. Abaixo são apresentados alguns padrões: Nomes de arquivos

Arquivos contendo os fontes Java terminam com a extensão .java. Todo arquivo fonte Java deve ter no máximo uma única classe public. Pode haver mais de uma classe por arquivo, porém somente uma pública. O nome do arquivo fonte java é case-sensitive, ou seja, deve respeitar letras maiúsculas e minúsculas, devendo também ter o mesmo nome da classe publica declarada dentro do mesmo.

Exemplo: Produto.java

Nomes de classes

Escolha nomes significativos, de tal forma que a simples leitura do nome já

crie uma expectativa acerca do que se pode esperar da classe. Use para isto um ou mais substantivos. O primeiro caractere de cada palavra utilizada para o nome da classe deve ser maiúsculo. Quando o nome de uma classe tiver mais de uma palavra as mesmas devem estar concatenadas.

Exemplo: NotaFiscal, Cliente, Item

Page 69: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Criando classes e objetos

3-7

Nomes de operações

Conselho similar pode ser dado à escolha dos nomes dos métodos: use

nomes significativos. Use verbos ou estruturas verbais que captem a ação principal contida no método. O nome deve representar a real utilidade desempenhada pelo método. A primeira letra do nome de uma operação deve ser em minúscula e a primeira letra de todas as demais palavras que compõem o nome da operação, caso existam, em maiúsculo.

Exemplo: getDescricao(), setPrecoFinal(…), imprimirRelatorio()

Nomes de atributos/variáveis

Use nomes curtos, mas que não sejam críticos. A primeira letra do nome da

variável deve ser em minúscula e a primeira letra de todas as demais palavras presente no nome deve ser maiúscula. Evite usar nomes de variáveis com uma única letra. O que você esperaria de uma variável de nome r ou x? O nome deve ser representativo e a simples leitura do mesmo leva à compreensão do papel desempenhado pela variável no aplicativo. A única exceção aceitável é para contadores em laços, ou variáveis temporárias de uso restrito.

Exemplo: nome, descricao, precoFinal, idade, dataNascimento

Nomes de constantes

O nome de constantes é definido de uma forma um tanto diferente. Toda

constante tem o seu nome escrito sempre com todos os caracteres em maiúsculo, e se o nome for composto por mais de uma palavra, as mesmas devem ser separadas pelo caractere ‘_’. Veja abaixo um exemplo:

Exemplo: TAMANHO_MAXIMO_VETOR = 100, BORDA = 4

Caracteres especiais

Números, sublinhado e dólar podem ser usados em nomes. A única

restrição é que o nome deve sempre começar por um caractere que seja diferente de um número. Mas evite o mau uso de tais caracteres especiais.

Page 70: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Criando classes e objetos

3-8

Nome de pacotes

Pacotes devem possuir nomes significativos e não devem ter seus nomes separados por caracteres como “_”. Seus nomes devem ser escritos sempre com todas as letras em minúsculo e os nomes de pacotes seprados pelo caractere ponto (“.”). Veja o exemplo abaixo:

Exemplo: com.targettrust.database

Observe que o nome do pacote foi iniciado com a palvra “com” e em seguida com a palavra targettrust. Normalmente começamos o nome de um pacote com o inverso do domínio da empresa. Isto explica o porque utilizar com.targettrust no início do nome do pacote.

Page 71: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Criando classes e objetos

3-9

Criando e importando pacotes

Java fornece o mecanismo de pacote como uma maneira de agrupar as classes relacionadas.

A declaração de pacote, caso exista, deve estar no início do arquivo de origem. Ela pode ser precedida apenas de espaços em branco e comentários. Somente uma declaração de pacote é permitida e influencia todo o arquivo de origem.

Os nomes de pacote são hierárquicos e separados por pontos. Convencionalmente, os elementos do nome de pacote estão

normalmente em letras minúsculas. O nome de classe, entretanto, geralmente começa com letra maiúscula e pode usar maiúsculas para separar as palavras do nome.

Veja o exemplo a seguir:

Código 3-5: Definindo um pacote para uma classe

Compilando e executando:

Código 3-6: Compilando um classe com pacote e realizando sua execução. A opção –d indica o deretório de destino para o byte-code

Código 3-7: Sintaxe para importar pacotes

package com.targettrust.java;

class HelloWorld { public static void main( String[] args ) { System.out.println( "Hello World!" ); } }

C:\> javac –d . HelloWorld.java C:\> java com.targettrust.java.HelloWorld Hello World!

package com.targettrut.java; import java.sql.*; import java.io.*; import java.net.*; import javax.swing.JFrame;

Page 72: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Criando classes e objetos

3-10

Page 73: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Criando classes e objetos

3-11

Static import

Este recurso presente a partir da versão 1.5 do java é extremamente útil para simplificar e facilitar a escrita de código. Permite utilizarmos os membros (atributos ou métodos) static sem que tenhamos que prefixar os membros com o nome da classe. Veja o exemplo abaixo:

System.out.println( Math.random() ); System.out.println( ( raio * raio) * Math.PI );

Código 3-8: Uso de operações static sem a importação dos membros static

Este código utilizando o static import ficaria assim: import static java.lang.Math.*; import static java.lang.System.*; ... out.println( random() ); out.println( ( raio * raio) * PI );

Código 3-9: Importanto os membros static da classe Math

Veja que o código acima fica mais claro e fácil de ser escrito. Esta facilidade de escrita do código deve ser utilizada mas com cuidado para não ser abusada, pois pode prejudidar a legibilidade do código das suas aplicações. Sempre que muitos membros static de uma classe forem ser utilizados é útil este recurso, mas se somente um ou dois membros forem ser utilizados o uso deste recurso não é aconselhável.

A importação dos membros static pode ser feito de forma genérica ou específica como mostra o código abaixo: 1 import static java.lang.Math.PI; 2 import static java.awt.BorderLayout.*;

Código 3-10: Importando a estrutura estatica de uma classe

Com o static import da linha 2 é possível se utilizar todas as constantes da

classe BorderLayout. Isto evita termos que escrever portanto o nome da classe cada vez que uma constante for utilizada.

Page 74: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Criando classes e objetos

3-12

Criando objetos

Neste momento do seu aprendizado iremos mostrar como pode ser criao um objeto de uma determinada classe para que você possa aproveitar melhor os passos seguintes do curso. Não iremos ainda aqui nos aprofundar neste assunto, visto que a criação de objeto é algo que merece um tempo maior de estudo. Veremos então como pode ser criado um objeto. ... Produto prod; prod = new Produto(); ...

Código 3-11: Criando um objeto da classe Produto

Observe no código acima a criação de um objeto que será referenciado por “prod”. Na primeira linha estamos fazendo a declaração de uma referência para um futuro objeto da classe produto. Esta referência irá receber um objeto que está sendo criado na linha segunte. A palavra reservada “new” é a responsável por alocar memória e construir o objeto da classe Produto. Logo depois de construído este objeto o endereço do mesmo ;e atribuído para a referência prod. Para criar um objeto precisamos da classe e no momento de criação do mesmo veja que logo depois deste nome de classe colocamos os sinais de parênteses. Esta criação também pode ser feita em uma única linha de código para simplificar o processo, como mostrado abaixo: ... Produto prod = new Produto(); ...

Código 3-12: Criand objeto da classe Produto em uma única linha

Agora em uma única linha você esta declarando uma referência para o objeto, criando o objeto e atribuindo o endereço de memória do mesmo para esta referência.

Page 75: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Criando classes e objetos

3-13

O que é a referência null?

Sempre que declararmos uma referência e esta não receber valor teremos um valor null “dentro” da mesma. Desta forma é importante estudarmos um pouco este valor null, pois muito erros em tempo de execução na linguagem java ocorrem em função desta palavra.

Considere o seguinte comando:

Código 3-13: Atribuindo null para a referência de Produto

Ele declara uma variável/referência prod e a inicializa com null. Isto indica que a variável de referência prod não se refere a nenhum objeto ainda, em outras palavras, ela somente foi delarada.

null é uma palavra reservada na linguagem Java. Você pode usá-la com o operador de igualdade para verificar se uma variável de referência já recebeu uma referência válida a um objeto ou mesmo para saber se duas referências

apontam para o mesmo objeto

Código 3-14: Teste entre uma referência e a palavra reservada null

Quando você tiver terminado de usar um objeto, você pode atribuir o valor null para a variável que o referencia. Isto indica que a variável não mais se refere ao objeto. Quando nenhuma referência houver para um objeto, o objeto será marcado como inacessível e será considerado pelo coletor de lixo (garbage collector). Iremos estudar com mais detalhes o coletor de lixo nos próximos capítulos.

Na prática, somente em casos muito especiais você precisa atribuir null para uma variável. A JVM automaticamente decrementa o número de referências ativas para um objeto sempre que a variável que o referencia recebe

Produto prod = null;

if( prod == null ) { ... ... } ... prod == prodRef ...

Page 76: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Criando classes e objetos

3-14

o valor null, sai de fora de escopo ou então recebe o valor de uma referência para outro objeto.

Page 77: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Criando classes e objetos

3-15

Atribuindo referências

Como mencionamos antes, quando você declara uma variável de referência para um objeto, esta variável tem o seu valor inicializado para null. Antes que você possa usar esta variável (ou seja, acessar o objeto a que ela referencia), você tem de inicializá-la. Todos os atributos de uma classe que forem de tipos compostos (Classes) serão inicializados automaticamente pela JVM no momento da criação de um objeto da classe para o valor null.

Quandor declaramos uma referência para um objeto e na mesma linha já criamos este objeto, estamos inicializado a referência com um valor diferente de null, ou seja, o endereço do objeto criado.V eja código abaixo:

Código 3-15: Criação do produto prod

Podemos também fazer atribuição de referência, para isto basta utiliza o operador de atribuição. Neste caso as duas referências irão apontar para o mesmo objeto. Veja o código abaixo:

Código 3-16: Atribuição da referência prod1 para prod2

Esta sintaxe está perfeitamente correta, mas vale frisar que há apenas um objeto Produto criado. Quando você atribui uma referência para um objeto para outra referência, você termina com duas referências para o mesmo objeto, e não uma cópia do objeto.

Você pode acessar o mesmo objeto através de ambas as referências, entretanto, há apenas um único objeto. Este objeto é conhecido como objeto de referência.

É importante se lembrar disto, principalmente ao passar uma referência para uma operação . Isto será visto em maiores detalhes adiante.

Você pode alterar uma referência (mudando o valor da variável de referência), sem que isto afete a outra referência (o valor da outra variável de referência).

Caso você precise de um outro objeto, ao invés de ter múltiplas referências para o mesmo objeto, você terá de criar este novo objeto.

Produto prod = new Produto();

Produto prod1 = prod2;

Page 78: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Criando classes e objetos

3-16

Visibilidade aplicada a classes

Encapsulamento é uma das palavras-chave para a orientação a objetos. Uma classe bem defina deve separar completamente a sua interface pública da implementação interna. Neste momento do estudo iremos mostrar quais são so tipos de encapsulamentos que uma classe pode receber. Certos de que a esta altura dos estudos você já conhece os tipos de encapsulamentos existentes vamos agora aplicar os mesmos para classe. A palavra visibilidade também pode ser aplicada para este assunto, uma vez que de acordo com o modificador que utilizaremos iremos tormar mais ou menos visível uma classe.

pacote/default

Esta visibilidade é a visibiliade padrão quando não se especifica nenhuma visibilidade. Ao contrátio de ontras linguagen onde a visibilidade padrão é public java define a visibilidade pacote/default. Se uma classe possuir esta visibilidade isto significa que a mesma pode ser utilizada somente por outras classes que estiverem dentro do mesmo pacote. Classes que estiverem em pacotes diferentes do pacote onde esta classe estiver não “saberão” que a mesma existe. No exemplo abaixo a classe email poderá ser utilizada somente por classes do pacote com.targettrust.comunicacao e nenhum outro pacote mais package com.targettrust.comunicacao; class Email { ... ... }

Código 3-17: Visibilidade de package aplicada a classes

Page 79: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Criando classes e objetos

3-17

public

Uma classe normalmente é declara como sendo pública, isto deixa a classe visível, ou seja, capaz de ser utilizada por qualquer outra classe do sistema, idependente do pacote onde a mesma se encontra. Recomenda-se que a classe sempre seja pública a não ser que você queira restringir o acesso de uso a esta classe. Quando em um arquivo fonte for delcarado mais de uma classe o nome do arquivo fonte deve levar o mesmo nome da classe pública que foi declarado neste. Lembre-se que não é possível declarar mais de uma clase pública em cada arquivo fonte. Veja o exemplo abaixo de uma classe pública: public class Email { ... ... } class Produto { ... ... }

Código 3-18: Duas classes declaradas no mesmo arquivo fonte

Page 80: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Criando classes e objetos

3-18

Definindo operações

Quando você define uma classe é necessário definir também as operações que farão parte desta classe. As operações são definidas dentro das chaves das classes. Cada operação terá uma implementação específica que é conhecida como método. Um método, portanto, é a implementação de uma operação.

Um método em Java é equivalente a uma função, procedimento ou sub-rotina em outras linguagens, com a diferença que ele deve ser definido dentro da declaração da classe. Em outras palavras, não existe em Java métodos globais (completamente desvinculados de uma classe). Todo método deve ser definido dentro de uma classe.

Anteriormente quando criamos uma classe, definimos uma operação chamada “main”, agora iremos estudar a anatomia das operações bem como definir outras operações em uma classe.

Anatomia de uma operação:

Abaixo temos uma operação definda dentro da classe Produto. Observe os elementos que fazem parte desta operação: public class Produto { public void foo(String arg, int cod) { } }

Código 3-19: Declaração da operação

Os elementos integrantes de uma operação são:

• Modificador de acesso: utilizados para restringirem o acesso as operações. Pode ser public, default, protected ou private.

public void foo(String arg, int cod) { }

Código 3-20: Visibilidade da operação

Page 81: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Criando classes e objetos

3-19

• Tipo de retorno: pode ser um tipo primitivo (como int ou char – tipos primitivos serão estudados mais adiante), ou um tipo composto (um objeto String ou Produto, por exemplo), ou mesmo não haver retorno algum. Neste caso deverá constar void como tipo de retorno. Em resumo: toda operação em java deve indicar o tipo de retorno.

public void foo(String arg, int cod) { } public String getDescricao() { }

Código 3-21: Tipo de retorno das operações

• Nome da operação: O nome da operação deve expressar o que a operação faz. Normalmente este nome deve ser um verbo ou estar no imperativo dando a idéia de uma ação.

public String getDescricao() { }

Código 3-22: Nome da operação

Parâmetros: representam os valores que podemos passar para a operação. Toda operação pode receber parâmetros, sendo assim a operação pode definir logo após o seu nome um ou uma lista de parâmetros. Se o método recebe vários parâmetros, cada um deles deve ser separado dos demais por vírgula. Uma operação também pode não receber parâmetros. Havendo ou não parâmetros, os mesmos devem ser representados entre parênteses.

public void foo(String arg, int cod) { } public String getDescricao() { }

Código 3-23: Parâmetros da operação

Page 82: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Criando classes e objetos

3-20

• Corpo da operação: é o local onde fica a implementação da mesma. Este código deve ficar entre chaves, que representam o início e fim do bloco.

public void foo(String arg, int cod) { System.out.println( arg ); System.out.println( cod ); } Código 3-24: Corpo da operação. Impressão dos valores passados como parâmetros

Page 83: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Criando classes e objetos

3-21

Comando return

O comando return é utilziado na linguagem java para que as operações possam retornar valores.

Um comando return aceita um valor simples ou uma expressão que deve ser compatível com o tipo de retorno do método em que este comando está

inserido.

Código 3-25: Comando return para retorno de método com ou sem valor de retorno.

Quando um comando de return é encontrado, o fluxo de execução abandona o método imediatamente, ignorando quaisquer comandos que existam entre o comando de return e o final do método (o fecha chaves do corpo do método).

Esta alteração do fluxo de execução pode ser usada mesmo em métodos que não retornam nenhum valor (métodos cujo tipo de retorno é void), com a finalidade de abandonar o método imediatamente.

Neste caso especial, o comando return não aceitará nenhum valor de retorno ou expressão (afinal o método é void).

public class Produto { public String getDescricao() { return "Nome: " + nome + " Preço: R$ " + preco; } public void setNome( String n ) { nome = n; return; } }

Page 84: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Criando classes e objetos

3-22

Visibilidade para operações

Operações assim como os atributos e as classes podem ter visibilidades. Para as operações são aplicados os seguintes tipos de visibilidades: private, public, protected e pacote/default. O uso destas visibilidades é freqüente para as operações uma vez que pode ser utilizada paa restringir o acesso a um objeto.

public

Esta visibilidade expõe as operações para serem chamadas de outros objetos. Acima quando criamos as operações você pode observar que as mesmas foram definidas como sendo públicas. Uma operação é definida sempre, por padrão, como sendo pública, veja o código abaixo: package com.targettrust.java; public class Produto { public void foo() { … } }

Código 3-26: Visibilidade pública

A operação foo() mostrada acima pode ser chamada a partir de qualquer outra classe independende do pacote onde se encontrar esta classe. Veja o código abaixo onde criamos um objeto para poder chamar esta operação: package com.targettrust.vendas; import com.targettrust.java.*; public class CriaObjetos { public static void main(String[] args) { Produto prod = new Produto(); prod.foo(); } }

Código 3-27: Criando um objeto de uma classe e chamando a iperação pública

Page 85: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Criando classes e objetos

3-23

private

A visibilidade private restringe o acesso a esta operação ao próprio objeto que a contém. Uma operação privada portanto não pode ser acessada por outro objeto a não ser aquela que a definiu. Operações privadas não são comuns e se existirei representam um serviço interno do próprio objeto. Veja abaixo como pode ser definida uma operação privada: public class Produto { private void foo() { … } }

Código 3-28: Visibilidade provada

Esta operação foo() é uma operação que pode ser chamada somente através de outras operações da própria classe, veja abaixo: public class Produto { private void foo() { … } public void salvar() { foo(); } }

Código 3-29: Chamando operação com visibiliade privada

Page 86: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Criando classes e objetos

3-24

O código abaixo não é permitido, pois veja que agora a operação foo() esta definida com sendo privada. public class CriaObjetos { public static void main(String[] args) { Produto prod = new Produto(); prod.foo(); } }

Código 3-30: Chamada de operação privada fora da classe

protected

O uso desta visibilidade, assim como para os atributos está ligada ao uso de herança, desta forma iremos deixar este tipo de visibilidade para ser demonstrado mais adiante quando estudarmos o mecanismo de herança. Uma operação protegida é uma operação visível para objetos de classes que estão no mesmo pacote daquela classe que define a operação ou para uma classe filha desta classe que contém a operação protegida.

package/defalut

Uma operação com visibilidade de pacote/default é uma operação que tem comportamento de pública dento do pacote que a contém. Normalmente uma operação não é definida como package, mas sim como public ou private. Para definir uma operação com esa visibilidade não se deve especificar nenhum modificador de acesso, isto a tornará default/package.

Veja abaixo na classe Produto como ficaria a operação com esta visibilidade: public class Produto { void foo() { … } }

Código 3-31: Visibilidade default

Page 87: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Criando classes e objetos

3-25

Definindo atributos

Os atributos de uma classe definem a estrutura dos objetos. Estes atributos são declarados dentro do bloco que define a classe. Veja no exemplo abaixo a declaração de alguns atributos para a classe produto: public class Produto { String descricao; float preco; boolean emVenda; }

Código 3-32: Atributos da classe produto

Observe que na declaração acima os atributos ficam dentro do bloco de código da claase. Estes atributos são atributos com visibilidade default. Logo estudaremos os tipos de visibilidade que podem ser aplicadas aos atributos. Estes atributos especificados acima são conhecidos como atrubutos de intância e para serem acessados precisam que um objeto da classe que os contém seja criado. Um atributo pode ser inicializado com valores já no momento da sua declaração como mostrado no código abaixo. Isto fará com que quando um objeto da classe que o contém for criado o mesmo já possua um determinado valor. O atributo emVenda irá possuir o valor true, neste caso, para todos os objetos criados public class Produto { String descricao; float preco; boolean emVenda = true; }

Código 3-33: Inicialização do atributo

Page 88: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Criando classes e objetos

3-26

Visibilidade aplicada a atributos

Os atributos são elementos que podem conter os quatro tipos de visibilidades definidos pela orientação a objetos. Vejamos agora o significado destes tipos de visibilidade aplicadas aos atributos.

public

Esta visibiliade irá tornar o acesso ao atributo disponível para qualquer outra classe que estiver em qualquer outro pacote. Isto significa que objetos gerados a partir desta classe que define o atributo público poderão ter os valores destes atributos modificados por qualquer outro objeto. Este tipo de encapsulamento/visibilidade não é o recomendado para atributos. Veja o exemplo abaixo com os atributos para a classe Produto sendo públicos: public class Produto { public String descricao; public float preco; public boolean emVenda; }

Código 3-34: Visibilidade pública para os atributos

Veja agora como seria o acesso a estes atributos em um pseudo-código. Observe que a palavra “prod” é utilizada para referenciar um objeto da classe Produto criado. public class Consulta { public static void main(String[] args) { Produto prod = new Produto(); prod.descricao = “Notebook”; prod.preco = 3500.0f; prod.emVenda = false; } }

Código 3-35: Acessando atributos com visibiliade pública

Page 89: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Criando classes e objetos

3-27

Page 90: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Criando classes e objetos

3-28

private

A visibilidade provate é a visibilidade recomendada pela orientação a objetos para os atributos de uma classe. Você estudou estes tipos de visibilidade e a importância do uso das mesmas nos cursos anteriores, então vejamos agora como ficaria esta visibilidade aplicada aos atributos. public class Produto { private String descricao; private float preco; private boolean emVenda; }

Código 3-36: Definindo atributos provados

O acesso agora aos atributos não poderia mais ser feito de forma direta como na visibilidade pública. Veja o código abaixo e observe que nas linhas onde tentamos acessar os atributos teríamos um erro sendo reportado pelo compilador dizendo que o atributo é privado e não pode ser acessado desta forma. public class Consulta { public static void main(String[] args) { Produto prod = new Produto(); prod.descricao = “Notebook”; prod.preco = 3500.0f; prod.emVenda = false; } }

Código 3-37: Acessando atributos privados

Como então deve ser feito o acesso a atributos privados. O acesso a atributos com visibilidade privada deve ser feito através de operações públicas que serão especificadas na classe. Já vimos como definir operações, então veja agora como ficaria o acesso a estes atributos. Primeiramente teríamos que modificar a classe Produto adicionando métodos públicos para fazer este acesso. Veja abaixo:

Page 91: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Criando classes e objetos

3-29

public class Produto { private String descricao; private float preco; private boolean emVenda; public void setDescricao(String novaDescricao) { descricao = novaDescricao; } public String getDescricao() { return descricao; } ... }

Código 3-38: Definindo operações para acesso aos atributos

Logo depois de modificarmos a classe Produto podemos fazer acesso a

seus atributos através das operações. Veja abaixo:

public class Consulta { public static void main(String[] args) { Produto prod = new Produto(); prod.setDescricao(“Notebook”); prod.setPreco(3500.0f); prod.setEmVenda(false); } }

Código 3-39: Utilizando as operações para acesso aos atributos

Page 92: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Criando classes e objetos

3-30

package/default

Um atributo com visibilidade de pacote/default é um atributo que pode ser acessado diretamente como se fosse público por classes que estiverem no memo pacote. Para definir um atributo com esta visibilidade não é necessário colocar modificador antes do mesmo. Este é o modificador padrão para visibilidades quando as mesmas não forem definidas. Abaixo veja a nova versão da classe Produto: package com.targettrust.java; public class Produto { String descricao; float preco; boolean emVenda; }

Código 3-40: Visibilidade default

Observe que a classe acima está dentro de um pacote chamado com.targettrust.java e que a mesma será utilizada por outra classe que está no mesmo pacote. package com.targettrust.java; public class Consulta { public static void main(String[] args) { Produto prod = new Produto(); prod.descricao = “Notebook”; prod.preco = 3500.0f; prod.emVenda = false; } }

Código 3-41: Acesso a visibilidade defalut

Page 93: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Criando classes e objetos

3-31

Agora se movermos a classe Consulta para outro pacote e fizermos a importação do pacote com.targettrust.java para tentar acessar os atributos nõa teremos sucesso.

package com.targettrust.exemplo; import com.targettrust.java.*; public class Consulta { public static void main(String[] args) { Produto prod = new Produto(); prod.descricao = “Notebook”; prod.preco = 3500.0f; prod.emVenda = false; } }

Código 3-42: Acessando atributo default fora do pacote

O código que temos para acessar os atributos é o mesmo que temos quando a classe é pública, mas agora como a classe Consulta está em pacote diferente, e os atributos de Produto tem a visibilidade de pacote/default o acesso não pode mais ser feito de forma direta. Neste caso se tivéssemos interesse em acessar os atributos a partir de outra classe fora do pacote teríamos que fornecer métodos públicos para isto.

protected

Esta visibiliade para ser entendida necessita o estudo do mecanismo de herança entre classes. Vamos deixar para mais tarde quando mostrarmos aqui este mecanismo para então dar exemplos de códigos com protected. Um atributo protegido é um atributo que terá visibilidade de pacote, mas também irá permitir o acesso direto a ele para classes que estiverem em pacotes diferentes daquele pacote onde está a classe que o define, desde que a classe fora do pacote seja filha da que contém o atributo.

Page 94: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Criando classes e objetos

3-32

Acessando atributos

O acesso a atributos de uma classe deve ser feito somente por operações definidas na mesma classe que contém este atributo. Desta forma devemos tornar os atributos de uma classe por padrão privados e as operações que irão acessá-los públicas.

Cada atributo irá possuir um par de métodos que chamamos de métodos de leitura e escrita ou getter e setter. Veja abaixo como ficaria a classe produto:

public class Produto { private int codigo; private String descricao; private float preco; public void setCodigo(int novoCodigo) { codigo = novoCodigo; } public int getCodigo() { return codigo; } public void setDescricao(String novaDescricao) { descricao = novaDescricao; } public String getDescricao() { return descricao; } public void setPreco(float novoPreco) { preco = novoPreco; } public float getPreco() { return preco; } }

Código 3-43: Definição da classe Produto

Page 95: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Criando classes e objetos

3-33

Comentários no código fonte

Os comentários de código fonte estão presentem em todas as linguagens de programação, e como java não poderia ficar de fora o mesmo possui 3 tipos de comentários. Os comentários são importantes pois são um mecanismo para o programador explicar dentro do fonte com as suas próprias palavras o que significa ou faz os elementos que o mesmo está escrevendo.

Java possui um tipo de cometário que pode ser utilizado por um gerador de documentação a fim do mesmo criar um conjunto de páginas HTML com informações sobre a classe. O programador interessado em utilizar aquela clase não precise olhar o fonte da mesma para saber do que ele dispõe, mas sim basta olhar em qualquer browser esta documentação em formato HTML.

Na linguagem java existem os seguintes tipos de comentários:

1 – Comentário de linha

2 – Comentário de múltiplas linhas

3 – Comentário de documentação

Comentário de linha

O comentário de linha é um comentário bastante prático e muito utilizado. Seve para podermos colocar em qualquer ponto do código uma documentação. No entanto esta documentação é feita somente em uma linha, não podendo haver múltiplas linhas como no anterior. Veja o exemplo abaixo: public class Produto { public float calcularPreco() { // para calcular o preço deve ser descontado o desconto preco = preco – desconto; ... } }

Código 3-44: Comentário de linha

Page 96: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Criando classes e objetos

3-34

Comentário de múltiplas linhas

O comentário de múltiplas linhas pode ser utilizado em qualquer ponto do código. Este tipo de comentário não fará parte da documentação gerado pelo javadoc. O programador pode escrever mais de uma linha documentando o código. Os caracteres /* e */ representam o início e fim deste tipo de comentário. public class Produto { public void imprimir() { /* Mostra os dados do produto. Estes dados mostrados são: nome, descrição e preço */ System.out.println(“Dados do produto:”); ... } }

Código 3-45: Comentário de múltiplas linhas

Comentário de documentação

Este tipo de cometário deve ser colocado antes do elemento que se quer documentar, ou seja antes da definição de uma classe ou operação. As marcações /** e */ indicam o início e fim de um comentário de documentação. Todo o conteúdo colocado dentro destas marcações será capturado pelo utilitário javadoc para montar a documentação da classe em formato HTML.

/** Classe para representar um produto da loja. Um produto deve conter sempre um código e uma descrição Criada dia 05-05-2005 */ public class Produto { /** Método para mostrar os dados de um produto */ public void imprimir() { } }

Código 3-46: Comentário de documentação para classe e operação

Page 97: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Criando classes e objetos

3-35

Os comentários de documentação podem ter algumas marcações especiais para serem capturadas pelo javadoc e adicionadas na documentação HTML da classe. Estas marcação são as seguintes: @return Representa o tipo de retorno de uma operação. Pode conter texto

para explicar o que é o tipo de retorno @param Representa o parâmetro de uma operação. Deve conter uma

descrição do que significa este parâmetro. Tabela 3-1: macros para documentação

Veja código de exemplo abaixo: public class Produto { /** Calcula o custo de um produto. @param arg um argumento a ser utilizado para calcular o custo @param cod código do produto a ser utilizado no calculo @return float indicando o custo do produto */ public float calcularCusto(String arg, int cod) { … } }

Código 3-47: Comentário de documentação para a classe Produto

Page 98: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Criando classes e objetos

3-36

Escopo das variáveis

Este é um assunto muitas vezes não abordado em materiais sobre java, porém de extrema importância. Nesta linguagem as variáveis quando forem declaradas irão estar visíveis dentro de um determinado escopo de código. Este escopo é delimitado por chaves que representam blocos de códigos. Isto significa que uma variável declarada dentro de um bloco de código é visível somente aquele bloco de código bem como a outros blocos que estiverem dentro deste.

Normalmente existe um bloco de código delimitado por chaves para representar o corpo de código de uma classe (veja na figura abaixo o escopo de classe) e de uma operação (veja abaixo escopo de método). Isto significa que se declararmos uma variável dentro do bloco da classe a mesma será visível a códigos que se encontrarem dentro daquele escopo de classe (não estamos aqui levando em consideração os tipos de encapsulamento). Dentro de um corpo de código para classes podemos ter operações definidas e estas operações possuem também seus blocos de códigos (escopo de método). Isto significa que se dentro do bloco de código de uma classe definirmos uma variável, esta variável poderá ser acessada normalmente dentro de qualquer bloco de código de uma operação que foi definido dentro do bloco da classe. Isto tudo pode ser resumido da seguinte maneira: uma operação pode chamar qualquer outra operação da classe ou mesmo acessar uma variável desta classe.

Podemos também definir dentro do escopo de um método outros blocos de código. Isto pode ser feito através do uso de chaves. Não é normal definirmos blocos de código desta maneira, mas esta mesma idéia pode ser utilizada para os comandos que possuem blocos de códigos como o “if”, “for”, “while”, etc...

Veja abaixo na figura a representação dos escopos.

Figura 3-1: Escopos de implementação.

Page 99: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Criando classes e objetos

3-37

public class Produto { private float preco; public void setPreco(float novoPreco) { preco = novoPreco; } }

Código 3-48: Acessando a variável preco

Observe no código acima o escopo onde foi definido o preço. Esta variável (podemos também chamar de atributo) foi definido dentro do escopo da classe, ou seja, dentro das chaves da classe. Pode, portanto, ser acessado por qualquer operação que estiver também definda dentro do escopo de classe, como a operação setPreco(...).

Veja agora o código abaixo ao qual adicionamos mais variáveis e outro escopo.

public class Produto { private float preco; public void setPreco(float novoPreco) { preco = novoPreco; x = 34; // Erro } public void foo(int y) { int x = 10; if ( x > y) { int res = x + y; } System.out.println( res ); // Erro } }

Código 3-49: Acessando variáveis fora de escopo

No código acima temos a declaraçõ de uma variável inteira x dentro do bloco de código da operação foo(...). Isto significa que esta variável somente poderá ser acessada por outros códigos que estiverem dentro desta mesma operação. Este tipo de variável é conhecida como variável local. Observe que na linha onde é atribuído o valor 34 ao x teremos um erro.

Page 100: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Criando classes e objetos

3-38

Neste mesmo código mostrado acima podemos observar que foi declarado um comando condicional if dentro da operação e que dentro deste comando declaramos uma variável res. Esta variável é uma variável local ao comando condicional, ou seja, é válida somente dentro deste comando, não podendo ser acessada fora do mesmo. Veja a linha onde tentamos imprimir o conteúdo da variável res, nesta linha teremos um erro de acesso.

Podemos definir “x” e “res” como sendo variáveis locais, enquanto preço pode ser definido como sendo uma variável de instância. Par6ametros de métodos também são considerados como sendo variáveis locais.

Page 101: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Criando classes e objetos

3-39

Passando Tipos Primitivos para Métodos

Quando um valor de tipo primitivo (int, char, etc.) é passado para o método, uma cópia deste valor preencherá o respectivo parâmetro do método. Se o método alterar o valor de seus parâmetros, esta alteração terá um efeito local: alterará apenas a cópia (o parâmetro formal ou argumento), mas o valor original permanecerá o mesmo.

Quando o método termina, todos os seus parâmetros são descartados e as variáveis originais presentes na chamada permanecem inalteradas.

O exemplo abaixo ilustra a maneira com que tipos primitivos são passados por valor para os métodos.

Código 5-20: Escopo de execução da variável preco.

Código 3-50: Escopo de execução da variável arg

O código à esquerda declara uma variável int chamada preco e atribui o valor 150 a esta variável. Quando preco é passada para foo(), uma cópia de seu valor corrente preencherá o parâmetro arg, que terá o valor inicial de 100.

Dentro de foo(), arg recebe o valor 55. Quando foo() termina, o parâmetro arg é descartado e o fluxo de execução retorna ao chamador.

A variável preco, definida no contexto do chamador, não foi afetada e tem ainda o valor de 100.

A saída do programa será, portanto, a seguinte:

int preco = 100; obj.foo(preco); System.out.println("preço = " + preco);

public void foo(int arg) { if(arg > 0 && arg < 2000) arg = 55; System.out.println("arg = " + arg); }

arg = 55 preco = 100

preco 100

arg 100

Page 102: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Criando classes e objetos

3-40

Passando Referências para Métodos

Quando você passa um objeto para um método, a referência para o objeto original é passada como argumento, e não uma cópia do objeto. Qualquer alteração que o método fizer valendo-se da referência recebida, alterará o objeto original. Quando o método terminar, todas as alterações feitas pelo método no objeto permanecerão.

O exemplo abaixo ilustra a maneira pela qual referências para objetos são passadas para métodos.

O código à esquerda cria um objeto Produto e armazena a referência para este objeto na variável p1. Neste exato instante, o título de p1 é "DVD” e o código é "1".

Quando p1 é passada para foo(), o método recebe a referência para o objeto Produto original. Dentro de foo(), através da variável de referência ref, o nome e o código são alterados. Quando foo() termina, o objeto Produto original referenciado por prod tem o título "CD" e o código "2".

Código 3-51: Escopo de execução do objeto prod

Código 3-52: Escopo de execução do objeto prod pela referência ref.

Produto prod = new Produto( “CD” ); prod.setCodigo( 1 ); obj.foo( prod );

public void food(Produto ref) { ref.setCodigo( 2 ); ref.setNome( "CD" ); }

prod

nome:"CD" codigo: 2

ref

Page 103: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Criando classes e objetos

3-41

Espaço para anotações

Page 104: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Criando classes e objetos

3-42

Exercícios

1. Neste exercício você irá criar uma classe para representar um Produto com a estrutura (atributos) descrita abaixo. Esta classe estará associada com outra classe, a ItemPedido. Item pedido possui o produto e a sua quantidade. No final você irá criar uma classe com método main para testar sua aplicação. Siga os passos abaixo para realizar o exercício.

Passo 1: Crie uma classe chamada Produto dentro de seu projeto. Esta classe deverá pertencer ao pacote com.targettrust.java. Passo 2: Defina nesta classe os seguintes atributos privados:

private String codigo private String descricao private float preco private boolean emVenda private float desconto

Passo 3: Crie operações públicas para acessar estes atributos permitindo que os mesmos possam ser lidos e modificados. Passo 4: Documente o código escrito por você. Use comentário de documentação para mostrar o que as operações realizam bem como seus parâmetros e tipo de retorno. Passo 5: Crie uma outra classe pública com o nome ItemPedido. Esta classe deve pertencer ao pacote com.targettrust.venda. Passo 6: Para esta classe declare os seguintes atributos privados:

private int quantidade private Produto produto

Passo 7: Crie operações públicas para acessar estes atributos de forma que seja possível modificar e ler os seus valores. Passo 8: Crie uma nova classe chamada Aplicação no pacote com.targettrust.java. Dentro desta classe declare o método main mostrado anteriormente na apostila. O método main é aquele que permite executar a classe.

Page 105: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Criando classes e objetos

3-43

Passo 9: Dentro do método main crie objetos da classe ItemPedido e Produto e em seguinda associe estes objetos. Lembre-se que um ItemPedido possui uma referência para um Produto. Defina valores para os outros atributos dos objetos. Passo 10: Crie na classe Aplicacao uma operação que seja capaz de receber como parâmetro um ItemPedido e faça a impressão das informações do objeto que esta operação receber. Passo 11: Gere a documentação utilizando o javadoc para as classes criadas no exercício.

Page 106: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Java Fundamentals

4-1

44.. CCoommaannddooss ddaa LLiinngguuaaggeemm

Page 107: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Comandos da Linguagem

4-2

Objetivos

• Conhecer os comandos da linguagem java • Compeender os comandos e saber o contexto no qual podem ser

utilizados • São estudados os seguintes comandos:

• switch

• while

• do

• for

• for-each

• break

• continue

• if

• else if

• Operador ternário

Page 108: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Comandos da Linguagem

4-3

Comandos

Os comandos da linguagem são comandos comuns a maioria das linguagens de programação. O objetivo deste capítulo é adaptar o aluno a sintaxe destes comandos na linguagem java. Para isto abxaixo aprensentamos os comandos:: switch, while, do, for, for-each, break, continue, return, if e else if.

Page 109: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Comandos da Linguagem

4-4

Comando if / else / else if

O comando if é o principal comando de controle de fluxo. Ele possibilita ao programador Java tomar decisões ou, mais precisamente, executar um comando somente quando uma determinada condição for verdadeira.

O comando if sempre vem sempre acompanhado de uma expressão (que é a condição que pende sobre a execução do comando) e um comando (que somente será executado se a expressão anterior for avaliada para verdadeiro). Se a expressão for verdadeira o comando é executado. Se a expressão for falsa, o comando é saltado.

Por exemplo:

Código 4-1: Comando if simples.

Embora pareça um pouco estranho, os parêntesis que envolvem a expressão são exigidos pela sintaxe do comando. Como já foi mencionado, um bloco de comandos delimitados por chave (comando composto) comporta-se como um comando simples, e pode ser sempre colocado onde um comando simples é esperado. Desta forma, o comando if também pode ser escrito assim:

Código 4-2: Comando if com expressão lógica e bloco de comandos.

Um comando if pode opcionalmente incluir a palavra reservada else seguida de um comando (simples ou composto). Neste caso, a expressão condicional é avaliada e, se for verdadeira, o comando que segue a palavra reservada if é executado e o comando que segue a palavra else é pulado.

Se a expressão for falsa o contrário ocorrerá: o comando que segue a palavra reservada if é pulado e o comando que segue a palavra reservada else é executado.

if(usuario == null) { usuario = "admin"; }

if( (endereco == null) || (endereco.equals("") ) ) { endereco = "[desc.]"; System.out.println("Endereço não encontrado"); }

Page 110: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Comandos da Linguagem

4-5

Código 4-3: Comando if/else simples.

Quando há vários comandos if/else aninhados é necessário alguma precaução para garantir que a cláusula else se refere ao comando if correto.

Considere as seguintes linhas:

Código 4-4: Comando if mal identado.

Infelizmente não está claro com qual if a cláusula else faz par. A identação sugere ser o primeiro if o par da cláusula else. E sugere erradamente, levando o programador a uma situação de erro.

A regra para o casamento dos pares if/else é bem simples. A cláusula else sempre faz par com o comando if mais próximo. Corrigindo a identação, para que represente corretamente os pares if/else, teremos:

Código 4-5: Comando if mal identado.

if(usuario != null) { System.out.println("Olá! " + usuario); }else { usuario = getNomeUsuario(); System.out.println("Olá! " + usuario + "Esta é sua primeira sessão" ); }

if(i == j) if(j == k) System.out.println("i é igual a k"); else System.out.println("i não é igual a j"); // ERRADO

if(i == j) if(j == k) System.out.println("i é igual a k"); else System.out.println("i não é igual a j"); // ERRADO

Page 111: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Comandos da Linguagem

4-6

Muito cuidado deve ser tomado, pois não há erro de sintaxe nos dois exemplos acima. São construções é perfeitamente legal. Só não ocorre o que o programador deseja. Ao trabalhar com comandos ifs aninhados use chaves a fim de tornar o código mais legível.

Código 4-6: Comando if identado corretamente.

if(i == j) { if(j == k) { System.out.println("i é igual a k"); } }else { System.out.println("i não é igual a j"); // CORRETO }

Page 112: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Comandos da Linguagem

4-7

Seqüência de Cláusulas else if

O comando if/else é útil para testar uma condição e escolher qual comando ou bloco de comandos executar. Mas, e se devemos escolher não um bloco entre dois, mas sim um entre vários? Para resolver este tipo de problema é comum usarmos uma seqüência de cláusulas else if.

Cláusulas else if não são uma novo comando da linguagem Java, ou mesmo uma sintaxe alternativa de um comando existente. Estas cláusulas são apenas o emprego inteligente do conhecido comando if/else associado a uma identação que facilite o entendimento.

Veja o exemplo abaixo:

Código 4-7: Comando if em sequência identado a esquerda.

Não há nada de especial no código acima. É apenas uma seqüência de comandos ifs, onde cada if é parte da cláusula else do comando anterior. No entanto, escrito desta forma o código fica bem mais legível e claro do que se fosse escrito com sucessivos aninhamentos (basta dar uma olhada no exemplo

abaixo).

if(n == 1) { // executa bloco de código 1 }else if(n == 2) { // executa bloco de código 2 }else if(n == 3) { // executa bloco de código 3 }else { // se todas as condições acima falham, então // executa bloco de código 4 }

if(n == 1) { // executa bloco de código 1 } else { if(n == 2) { // executa bloco de código 2 } else { if(n == 3) { // executa bloco de código 3 } else { // se todas as condições acima falham, então // executa bloco de código 4 } } }

Page 113: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Comandos da Linguagem

4-8

Código 4-8: Comando if em sequência identado em relação a blocos de código.

Page 114: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Comandos da Linguagem

4-9

Operador ternário

Java também define um operador ternário, chamado freqüentemente de operador condicional. Funciona como um comando if dentro de uma expressão. Seus três operandos são separados por um ponto de interrogação ‘?’ e por dois pontos ‘:’. O segundo e o terceiro operando devem ser do mesmo tipo.

Veja o código abaixo:

int x, y; ... String res = “”; if ( x > y ) { res = “X é maior que Y”; }else { res = “Y é maior que X”; } ... System.out.println( res );

Código 4-9: Comando if else a ser transformado em operador ternário Agora vamos ver o mesmo código fazendo usto do operador ternário: int x, y; ... String res = (x > y)?“X é maior que Y”:“Y é maior que X”; ... System.out.println( res );

Código 4-10: Expressão com operador ternário Observe que o código é bem mais enxuto para este caso de if..else

Page 115: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Comandos da Linguagem

4-10

Comando switch

O comando if provoca um desvio no fluxo de execução de um programa. Você pode usar múltiplos comandos ifs, como mostrado na seção anterior, para executar desvios múltiplos de execução. Entretanto, esta nem sempre é a melhor solução especialmente quando todos os desvios dependem do valor de uma única variável.

Neste caso é ineficiente conferir repetidas vezes o valor de uma mesma variável em múltiplos comandos ifs.

Uma solução melhor é usar o comando switch. Embora a sintaxe deste comando não possua a mesma elegância apresentada por outros comandos da linguagem, a praticidade deste tipo de construção o torna extremamente útil. Se você não está familiar com este comando, talvez já conheça, no entanto, a idéia que está por detrás dele.

O comando switch possui uma expressão inteira e um corpo que contém vários pontos de entrada numerados. A expressão é avaliada e o fluxo de execução salta para o ponto de entrada especificado com o valor avaliado. O comando switch seguinte é equivalente ao uso repetido de comandos if e

else/if, como mostrado na seção anterior.

Código 4-11: Comando switch padrão de inteiros utilizando break

Como você pode ver a partir deste exemplo, os vários pontos de entrada do comando switch são rotulados ou com a palavra reservada case seguida de um valor inteiro e dois pontos, ou então da palavra reservada default seguida de dois pontos.

switch(n) { case 1: // começa aqui se n == 1 // executa bloco de código 1 break; // para aqui

case 2: // começa aqui se n == 2 // executa bloco de código 2 break; // para aqui

case 3: case 4: // começa aqui se n == 3 // executa bloco de código 3 break; // para aqui

default: // se todas as condições acima falham, então // executa bloco de código 4 break; // para aqui }

Page 116: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Comandos da Linguagem

4-11

Quando o comando switch é executado, o interpretador Java calcula o valor da expressão entre parêntesis e então procura pelo rótulo case que tenha especificado este valor.

Se ele consegue encontrar tal rótulo, o fluxo de execução é transferido para o bloco de código que tem início no primeiro comando após o rótulo.

Se ele não encontra um rótulo com o valor da expressão avaliada, o fluxo de execução salta para o primeiro comando após o rótulo especial default. Ou, caso um rótulo default não tenha sido definido, o fluxo de execução salta totalmente para fora do comando switch.

Observe o uso da palavra reservada break ao final de cada rótulo case no exemplo anterior. O comando break será descrito mais adiante, mas, neste caso, ele faz com que o fluxo de execução salte para fora do corpo do comando switch.

Os rótulos case em um comando switch especificam somente o ponto de entrada para o bloco de código a ser executado. Os rótulos cases não são blocos independentes de código, e não possuem um ponto de término implícito. Portanto, você deve especificar o fim de cada rótulo com um comando break ou equivalente.

Na ausência de um comando break, a expressão é avaliada e o fluxo de execução salta para o bloco de código que tem seu início logo após o rótulo que define a expressão avaliada, e a execução continua até o final do comando switch.

Em raras ocasiões se revela útil escrever código em que a execução atravessa mais de um rótulo. Em 99% dos casos, depois de encontrado o rótulo e executado o bloco de código associado a este, a execução deve deixar o comando switch por força de um comando break. Lembre-se, portanto, de sempre verificar se há um comando break após cada rótulo, garantindo a saída correta do comando e impedindo que o fluxo de execução passe por todos os rótulos do comando.

Um comando switch pode ter mais de uma cláusula case rotulando um mesmo comando.

Considere o seguinte método:

boolean respostaSimOuNao( char resposta ) { switch( resposta ) { case 's': case 'S': return true; case 'n': case 'N': return false; default: return false; //por default a resposta será false } }

Page 117: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Comandos da Linguagem

4-12

Código 4-12: Comando switch de char sem utilização de break e com comando return.

Há algumas importantes restrições sobre o comando switch e os rótulos cases. A expressão associada com o comando switch deve ter um tipo byte, char, short ou int. Valores booleanos ou reais não são suportados, nem o tipo long, apesar de ser um tipo inteiro.

Os valores associados com cada rótulo case devem ser ou constantes, ou expressões constantes avaliáveis em tempo de compilação. Um rótulo case não pode conter expressões avaliáveis em tempo de execução, tais como variáveis ou chamadas de métodos.

Os valores presentes nos rótulos cases devem estar compreendidos na faixa de valores do tipo usado na expressão do comando. Por fim, dois rótulos cases não podem ter o mesmo valor, nem um comando switch pode ter mais de uma cláusula default.

Page 118: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Comandos da Linguagem

4-13

Comando while

Assim como o comando if é o principal comando de controle de fluxo, permitindo ao programador tomar uma entre várias decisões, o comando while é o principal comando de iteração da linguagem Java e permite ao programador executar um bloco de código reiteradas vezes.

Ele possui a seguinte sintaxe:

Código 4-13: Estrutura do comando while.

O comando while começa por avaliar a expressão entre parêntesis. Se esta expressão é avaliada para falso, o fluxo de execução pula o corpo do comando while e passa a executar o próximo comando definido no programa. Se, no entanto, a expressão é verdadeira, o corpo do laço while é executado e a expressão entre parêntesis é reavaliada. Este ciclo continua enquanto a avaliação da expressão resultar verdadeiro.

Quando a expressão se tornar falsa, a execução do comando while termina e o fluxo de execução passa para o próximo comando. Você pode criar um laço infinito com a sintaxe while(true) (pois a expressão sempre é verdadeira).

Um exemplo de um laço que imprime os números de 0 a 9:

Código 4-14: Comando while com teste lógico para impressão de inteiros entre 0 e 9.

Como você pode ver, a variável cont começa em 0, neste exemplo, e é incrementada cada vez que o corpo do laço é executado. Após o laço ter sido executado 10 vezes, a expressão do comando while se torna falsa (i assume o valor 10), o comando while termina, e o fluxo de execução passa para o próximo comando do programa.

A maior parte dos laços tem uma variável contadora, como i. Os nomes de variáveis: i, j e k são usados, na maioria das vezes, para tais variáveis contadoras, embora você possa escolher um nome mais claro.

while(expressao) { comandos }

int i = 0; while(i < 10) { System.out.println(i); i++; }

Page 119: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Comandos da Linguagem

4-14

Comando do

O comando do é bastante similar ao comando while. A diferença é que, no comando do, o teste da expressão é feito no final do laço.

Isto significa que o corpo do laço é executado pelo menos uma vez. Eis a sintaxe do comando:

Código 4-15: Estrutura do comnado do/while.

Há algumas diferenças a se observar entre o laço presente no comando do e o laço presente no comando while. O laço do comando do requer tanto a palavra reservada do para marcar seu início, quanto a palavra reservada while para marcar o seu término e introduzir a expressão condicional do laço.

Ao contrário do laço do comando while, o laço do comando do sempre termina com um ponto e vírgula. Isto obviamente ocorre pelo fato de a expressão condicional ser colocada no final do comando.

O laço abaixo gera a mesma saída que o código apresentado para o comando while:

Código 4-16: Comando do/while com teste lógico no final para impressão de inteiros entre 0 e 9.

Observe que o comando do é bem menos usado que o comando while. Isto acontece porque, na prática, é incomum encontrarmos situações em que se deseje que o corpo do laço seja executado pelo menos uma única vez.

do { comandos } while(expressao);

int i = 0; do { System.out.println( i ); i++; } while( cont < 10 );

Page 120: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Comandos da Linguagem

4-15

Comando for

O comando for fornece uma construção de iteração que é, na maioria das vezes, mais conveniente que os laços while e do. O comando for tira vantagem de haver um padrão de iteração bastante freqüente. A maior parte dos laços possui um contador, ou algum tipo de variável de estado, que é inicializado antes da execução do laço e incrementado, ou de alguma forma alterado, após o término da execução do corpo do laço e antes da reavaliação da expressão condicional associada ao laço.

Os passos de inicialização, teste e atualização constituem as principais manipulações feitas sobre as variáveis do laço e integram a sintaxe do comando

for.

Código 4-17: Estrutura do comando for

Colocar as expressões de inicialização, teste e atualização no início do laço é algo que facilita a compreensão do que está ocorrendo no corpo do laço, e evita erros tais como esquecer de inicializar as variáveis do laço.

O interpretador Java descarta os valores das expressões de inicialização e atualização, logo, para que estas expressões sejam úteis, elas devem ter efeitos colaterais.

A expressão de inicialização é tipicamente uma expressão de atribuição, enquanto a expressão de atualização é usualmente uma expressão de incremento, decremento ou atribuição.

O seguinte laço imprime os números de 0 a 9, como os exemplos anteriormente colocados para os comandos while e do:

Código 4-18: Comando for com teste lógico e incremento para impressão de inteiros entre 0 e 9.

Observe como esta sintaxe coloca todas as informações importantes sobre a variável do laço em uma única linha, facilitando a compreensão do que ocorre no corpo do laço.

for( declaração e inicialização; teste; atualização ) { }

for( int i = 0; i < 10; i++ ) { Sytem.out.println( i ); }

Page 121: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Comandos da Linguagem

4-16

Colocar a expressão de atualização da variável do laço na sintaxe do próprio comando for simplifica também o corpo do laço, permitindo que este possa ser expresso, muita das vezes, através de um único comando simples, sem a necessidade do uso de um bloco de código entre chaves.

O comando for suporta sintaxes alternativas que ajudam ainda mais facilitar o seu uso. Pelo fato da maioria dos laços usar as variáveis de laço apenas dentro do corpo do laço, o comando for permite que a expressão de inicialização contenha uma declaração completa de variáveis.

O escopo das variáveis declaradas na expressão de inicialização de um comando for se restringe ao corpo do laço e tais variáveis não mais podem ser acessadas fora do comando.

Código 4-19: Comando for com escopo de variável local (i).

Além do mais, a sintaxe do comando não restringe a utilização do comando a laços com apenas uma variável. Tanto a expressão de inicialização quanto a de atualização podem conter, em verdade, a inicialização e atualização de mais de uma variável, desde tais variáveis venham separadas por vírgulas.

Por exemplo:

Código 4-20: Comando for com expressão utilizando o índice e variáveis locais.

Muito embora todos os exemplos de utilização do comando apresentem contadores numéricos, os laços construídos com o comando for não se restringem apenas à utilização de contadores.

As expressões de inicialização, teste e atualização do comando for são todas elas opcionais. O caractere de ponto e vírgula que separa tais expressões é, no entanto, obrigatório. Se a expressão de teste é omitida, presume-se que ela é sempre verdadeira.

Com isto, um laço infinito pode ser escrito desta forma:

Código 4-21: Comando for com loço infinito.

for( int i = 0; i < 10; i++ ) { Sytem.out.println( i ); }

for( int i = 0, j = 10; i < 10; i++, j-- ) { sum += i * j; }

for( ;; ) // for infinito

Page 122: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Comandos da Linguagem

4-17

Page 123: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Comandos da Linguagem

4-18

Comando “for-each”

O novo for é um laço de repetição mais fácil e bonito de escrever. Este

substitui o laço for atual de uma forma mais elegante para iterar sobre coleções. Observe o código abaixo que nos permite iterar uma coleção de alunos através do laço for tradicional: Collection<Aluno> c = new ArrayList<Aluno>(); ... for (Iterator<Aluno> i = c.iterator(); i.hasNext(); ) { System.out.println( i.next().getNome() ); }

Código 4-22: Comando for a ser transformado em for-each

Veja que uma simples tarefa de iterar uma coleção demanda um volume considerável de código. Agora observe a mesma versão deste código utilizando o laço “for-each” juntamente com o novo “import static”: Collection<Aluno> c = new ArrayList<Aluno>(); ... for ( Aluno a : c ) { out.println( a.getNome() ); }

Código 4-23: Comando for-each, mais simples que for

O sinal de “:” é lido com “em”. Desta forma o código acima pode ser lido da seguinte forma: “Para cada aluno a em c”. For-each também pode ser aplicado a arrays. Neste caso você pode iterar um array da seguinte forma: int[] notas = {2, 5, 7, 9, 4, 18}; int total = 0; for( int n : notas) { total += n; } out.println( total ); Código 4-24: For-each para somar notas

Page 124: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Comandos da Linguagem

4-19

Comando break

O comando break é utilizado para transferir o controle para fora do corpo do comando de laço ou switch mais próximo, transferindo imediatamente o controle para o primeiro comando após o corpo do laço ou switch. É usado, assim, para prematuramente sair de qualquer tipo de laço.

Este comando é muito útil para abortar um laço quando algum evento ocorre durante a execução do corpo deste laço.

Código 4-25: Estrutura do comando break

O seguinte trecho de código utiliza o comando break junto ao comando while. Ele imprime números que juntos somam um valor menor que 200, iniciando

em 0.

Código 4-26: Comando break finalizando um loço while

O comando break é também utilizado junto ao comando switch, para sair do corpo do comando. O trecho a seguir demonstra este uso.

Código 4-27: Comando break finalizando um comando switch

O comando break pode ser utilizado também seguido por um label que especifica um comando presente no método. Com o uso do comando break

break;

int i = 0; int total = 0; while( i < 100 ) { total += i; // total = total + i; if( total >= 200 ) { break; } System.out.println( i ); i++; }

switch( resposta ) { case 's': case 'S': System.out.println("Resposta SIM.");

break; case 'n': case 'N': System.out.println("Resposta NÃO."); break; default: System.out.println("Resposta não reconhecida."); }

Page 125: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Comandos da Linguagem

4-20

associado a um label, é possível interromper qualquer laço dentro da definição do método, e não somente o laço mais próximo.

Para utilizar o comando break com label, o label deve ser inserido antes do comando que se deseja interromper. O label pode ser qualquer identificador válido, seguido por “:”.

Um comando break especificando este label causará um pulo para o primeiro comando após o fim do corpo do comando com este label.

Código 4-28: Estrutura de comando break para quebra de laços nomeados

O trecho de código a seguir exemplifica este uso. Após o múltiplo dos inteiros i e j atingir um valor maior que 200, o comando for associado ao label comandoFor é interrompido (comando for mais externo) e a linha indicando que o múltiplo foi atingido será impressa.

Código 4-29: Comando break para quebra de laço for externo “comandoFor”.

O comando break com label é muito utilizado para interromper laços aninhados. Contudo, embora este seja um mecanismo válido, ele pode levar a um código que não é claro e de difícil manutenção, sendo melhor evitá-los repensando a lógica do laço.

label: comando {

... break label; ...

}

comandoFor:

for( int i = 0; i < 100; i++ ) { for( int j = 0; j < 100; j++ ) { System.out.println(i*j); if (i * j >= 200) { break comandoFor; } } } System.out.println( "Fim do Comando FOR" );

Page 126: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Comandos da Linguagem

4-21

Comando continue

O comando continue é usado para transferir o controle para o fim do corpo do laço, antes da re-avaliação da expressão de teste. Causa, assim, a interrupção da interação do laço corrente e o pulo para a próxima interação do laço.

Código 4-30: Estrutura do comando continue.

O trecho a seguir exemplifica o seu uso. Neste exemplo, o comando continue é utilizado para interromper a execução do resto do corpo do comando for em todos os números pares.

Ao final, a soma de todos os números ímpares positivos menores que 10 é apresentada.

Código 4-31: Comando continue reiniciando o laço for na próxima iteração de i

O comando continue deve ser utilizado com cuidado, pois o algoritmo resultante se torna pouco estruturado e de difícil manutenção.

O comando continue pode, assim como o break, ser utilizado com um label. Um comando continue com label causará a interrupção da interação corrente e o pulo para a próxima interação do laço associado ao label.

continue;

int total = 0; for( int i=0; i < 10; i++ ) { if( i % 2 == 0 ) { continue; } total = total + i; } System.out.println( total );

forExterno:

for( int i = 0; i < 100; i++ ) { for( int j = 0; j < 100; j++ ) { System.out.println( i*j ); if( i * j >= 200 ) { continue forExterno; } } } System.out.println( "Fim do FOR Externo" );

Page 127: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Comandos da Linguagem

4-22

Código 4-32: Comando continue para reinício de laço for externo “forExterno” no próximo índice de i

Page 128: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Comandos da Linguagem

4-23

Espaço para anotações

Page 129: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Comandos da Linguagem

4-24

Exercícios

1. Este exercício fará com que você altere as classes criadas no capítulo anterior adicionando algumas validações as suas operações.

Passo 1: Na classe Produto faça uma validação do parâmetro passado para operação que altera o preço do Produto. Não permita preços negativos. Valide também o código do Produto. Este deve possuir no máximo 6 caracteres.

Passo 2: Na classe ItemPedido, não permita atribuir através do método “set” um item do pedido ao produto se este não estiver em vendas. Faça o objeto item pedido “recusar” (não realizar a atribuição) o produto.

Passo 3: Agora faça uma alteração na classe Aplicacao para que a mesma ao imprimir os atributos booleanos imprima as palavras “Sim” e “Não” ao invés de true/false. Para isto utilize o operador ternário. Compile e teste a aplicação.

Passo 4: Altere um dos objetos produto que você criou para que o mesmo não esteja mais em vendas. Rode novamente a sua aplicação e verifique que para o pedido com o qual você tentou associar um produto que não estava em venda não sairá dados do produto. Nesta execução a JVM lancará também uma exception (NullPointerException).

Passo 5: Altere o código agora que faz a impressão das informações de um ItemPedido na classe Aplicacao para que quando um ItemPedido não tenha um produto seja impresso uma string mostrando isto.

2. Crie uma classe com o nome GeradorSenhas para que nesta seja possível gerar senhas através de um laço de repetição.

Passo 1: Crie uma classe pública chamada GeradorSenhas no pacote com.targettrust.java e nesta classe declare o método main para que a mesma possa ser executada.

Passo 2: Utilizando um laço de repetição a sua escolha (for, while, ..) faça a geração de 10 senhas randômicas com no máximo 8 díditos.

Dica para gerar números randomicamente:

Utilize a classe Math do pacote java.lang. Esta possui um método chamado random() que gera números aleatórios entre zero e um, excluindo o inteiro um. Veja a documentação JAVADOC para mais detalhes.

Page 130: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Comandos da Linguagem

4-25

Page 131: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Comandos da Linguagem

4-26

Page 132: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Java Fundamentals

5-1

55.. AApprrooffuunnddaannddoo oo eessttuuddoo ssoobbrree CCllaasssseess

Page 133: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Aprofundando o estudo sobre classes

5-2

Objetivos

• Estudar overloading e overriding

• Como utulizar métodos construtores

• Compreender a referência this

• Estudar o método destrutor finalize

• Criar operações com escopo de classe e instância

• Compreender o mecanismo de herança

• Utilizar o recurso de varargs

• Aplicar o polimorfismo

• Compreender o modificador final

• Estudar as enumerations

Page 134: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Aprofundando o estudo sobre classes

5-3

Visão Geral

Métodos de instância são o fundamento para o encapsulamento de classes e peças chaves para fornecer uma interface consistente. Classes definidas através de técnicas adequadas de encapsulamento fornecem métodos de instâncias como o único meio de se acessar e alterar o estado de um objeto.

Permitir o acesso direto às variáveis de instância de uma classe, sem que seja necessário invocar métodos para tal, é uma técnica de programação perigosa, pois não garante um estado sempre consistente para o objeto (o usuário não fica restrito às regras de negócios definidas na manipulação do objeto).

A sobrecarga permite que uma chamada a um método possua diferentes comportamentos de acordo com os parâmetros passados. Suponha, por exemplo, a classe Cliente.

O método comprar() desta classe pode ter comportamentos distintos dependendo dos parâmetros recebidos.

Se a chamada for comprar(dinheiro), o comportamento invocado será provavelmente um pagamento à vista, enquanto se for comprar(cheque), outro será o comportamento invocado, fazendo com que o débito de pagamento possa ser realizado em um dia posterior.

Sobrecarga é uma técnica poderosa, ao permitir que a classe tenha uma aparência uniforme para o mundo externo.

Construtores garantem que, a despeito de quem cria o objeto, o objeto terá as características esperadas para a classe.

Ao se criar um objeto, o método construtor é implicitamente chamado, oferecendo um local adequado para as rotinas de inicialização. Isto é ponto chave para programação orientada por objetos, já que é impossível saber quem criará novos objetos das classes que você definiu.

Page 135: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Aprofundando o estudo sobre classes

5-4

Overloading – sobrecarga de operação

Dois ou mais métodos em uma classe podem ter o mesmo nome, desde que tenham assinaturas diferentes. A assinatura de um método é formada por seu nome, juntamente com o número, tipo e ordem dos parâmetros. O tipo de retorno do método não é considerado como parte da assinatura.

A definição de dois ou mais métodos com o mesmo nome, mas com assinaturas diferentes é conhecida como sobrecarga de métodos (method overloading). Esta técnica é útil, pois oferece uma interface unificada da classe para o mundo externo.

O método exato a ser chamado é determinado pelos parâmetros presentes na chamada, ou seja pela assinatura. Sem a técnica de sobrecarga, cada método exigiria um nome único, tornando mais difícil a codificação. Se você quisesse, por exemplo, recuperar informações sobre um cliente usando como chave de pesquisa o ID do cliente ou o nome, teria de escrever métodos com nomes distintos: getClientePorNome(nome) e getClientePorID(id).

Usando sobrecarga, os dois métodos podem ter o mesmo nome getCliente(), um esperando o parâmetro id e o outro esperando o parâmetro nome, como mostrador abaixo:

public class ClienteDB { public Cliente getCliente(String nome) { ... } public Cliente getCliente(int id) { ... } }

Código 5-1 : Overloading da operação getCliente()

Quando o usuário de uma classe chamar um método sobrecarregado, o compilador escolherá o método correto a ser chamado analisando os parâmetros passados na chamada e comparando tais parâmetros com os esperados por cada um dos métodos com aquele nome na definição da classe.

Se o compilador não conseguir um “casamento compatível”, mesmo após efetuar as conversões implícitas permitidas pela linguagem, um código de erro será retornado. Do contrário, se mais de um casamento é possível, o compilador reclamará e assinalará erro de ambigüidade na definição do método.

Métodos sobrecarregados não podem ser diferenciados exclusivamente pelo tipo de retorno. Se a única diferença entre a declaração de dois métodos

Page 136: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Aprofundando o estudo sobre classes

5-5

for o tipo de retorno, o compilador retornará um erro e não aceitará a construção.

A distinção entre métodos sobrecarregados deve sempre ter por base o número e os tipos de parâmetros esperados.

Código 5-2: Sobrecarga de métodos.

public class Produto { private float preco; public float getPreco() { ... } public float getPreco( float desconto ) {

... } }

sobrecarga de método

Page 137: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Aprofundando o estudo sobre classes

5-6

Métodos construtores

Métodos construtores são chamados quando um objeto da classe estiver sendo criado. Podem ser utilizados para realizar algo no momento de criação do objeto, como por exemplo, inicializar atributos do mesmo para determinados valores.

O construtor é um método especial chamado automaticamente pelo ambiente de execução Java quando um objeto é criado. Um construtor sempre tem o mesmo nome que a classe. Ele pode esperar nenhum, um ou vários parâmetros, mas não pode ter nenhum tipo de retorno. Veja no código abaixo a declaração de um construtor:

public class Produto { Produto( ) { ... } }

Código 5-3: Definindo construtores

O construtor acima é conhecido como construtor default. O que acontece se um construtor não é fornecido? Caso nenhum construtor seja fornecido, Java supre esta ausência com um construtor default. Este construtor não recebe nenhum parâmetro e não executa nenhuma tarefa de inicialização.

É possível colocar dentro deste construtor um código a ser executado no momento de criação do objeto. Assim quando o objeto da classe produto for criado utilizando o construtor acima este código será executado. Veja como pode ser criado um objeto utilizando o construtor acima:

public class CriaObjeto { public static void main(String[] args) { Produto prod = new Produto(); } }

Código 5-4 : Criando um objeto e chamando o construtor

Observe que o código acima já havia sido utilizado anteriormente, mas agora você pode perceber que estamos chamando o construtor default no momento da criação do objeto.

Page 138: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Aprofundando o estudo sobre classes

5-7

Se você desejar, poderá fornecer mais construtores na mesma classe. Desta maneira se fornecer algum construtor o compilador não mais ir;a gerar o construtor default.

Entretanto, na maioria das vezes, será necessário declarar um ou mais construtores para a classe, a fim de permitir diferentes formas de criação do objeto, como mostrado no código abaixo a criação de quatro objetos da classe produto de quatro formas diferentes:

Código 5-5: Sobrecarga de construtores de Produto

Para permitir que o usuário crie objetos desta maneira, será necessário fornecer os contrutores na classe Produto e que inicialize o estado do objeto Produto com as opções fornecidas.

Construtores geralmente são declarados como public, salvo quando se deseja restringir quem pode criar objetos da classe. Veja abaixo um exemplo de construtor para a primeira e a segunda inicialização acima:

public class Produto { private String descricao; private int codigo; private float preco; public Produto(int c, String d, float p ) { codigo = c; descricao = d; preco = p; } public Produto(int c, String d) { codigo = c; descricao = d; } }

Código 5-6 : Construtores da classe Produto

Observe o código acima e veja que além de termos definido construtores na classe Produto para dentro dos mesmos fazer a inicialização de um produto, também temos overloading de construtores.

Produto prod1 = new Produto( 1, "CD", 45.50f ); Produto prod2 = new Produto( 2, "DVD" ); Produto prod3 = new Produto( "VHS" ); Produto prod4 = new Produto();

Page 139: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Aprofundando o estudo sobre classes

5-8

Page 140: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Aprofundando o estudo sobre classes

5-9

Referência this

Esta referência representa um objeto da própria classe. O this referencia o objeto corrente. Todos os objetos “possuem” o this.

Todos os métodos de instância recebem um parâmetro implícito chamado this, que pode ser usado dentro do método de instância para se referir ao objeto corrente. O objeto corrente é aquele cujo método foi invocado. O parâmetro this é uma referência implícita para objeto chamado e, como tal, não é necessário na maioria dos casos.

Código 5-7: Referência implícita this do objeto invocado.

Dentro de um método de instância, todas as referências não qualificadas para variáveis de instância ou métodos de instância estão implicitamente associadas com a referência this. Os dois comandos dentro do método setNome(), apresentados abaixo, são equivalentes:

Código 5-8: Referência implícita this para representar variáveis de instância.

public class Produto { public void setNome(String nome) { this.nome = nome; } } public void metodo() { Produto p1 = new Produto(); Produto p2 = new Produto(); p1.setNome( "CD" ); p2.setNome( "DVD" ); }

public void setNome( String nome ) { nome = nome; // ERRO! this.nome = nome; // Forma correta }

p1 nome:"CD"

p2 nome:"DVD"

this

Page 141: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Aprofundando o estudo sobre classes

5-10

Há duas situações em que você deve usar explicitamente a referência this:

• O nome de uma variável de instância é escondido por uma parâmetro formal, de mesmo nome, do método de instância. Suponha, por exemplo, uma classe que tenha uma variável de instância nome, e um método de instância que recebe uma variável também chamada nome. O parâmetro formal nome deste método esconde a variável de instância nome. Qualquer referência para nome, dentro deste método, acessará o parâmetro formal, não à variável de instância. Para acessar a variável de instância, você deve usar this.nome.

• Quando você precisa passar uma referência para o objeto corrente como parâmetro de um outro método

Page 142: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Aprofundando o estudo sobre classes

5-11

Compartilhando código entre Construtores

Um construtor pode chamar outro construtor da mesma classe usando a sintaxe this().

Código 5-9: Referência this invocando o construtor da própria classe de acordo com os tipos de parâmetros.

O primeiro construtor chama o segundo construtor passando “vazio” como parâmetro. O segundo construtor copia a referência para o objeto String na variável nome. Esta técnica garante que o nome default para todos os objetos Produto seja uma string vazia sem a necessidade de se duplicar código em múltiplos construtores.

A sintaxe this() minimiza a necessidade de se duplicar código nos construtores. Esta técnica é especialmente útil se a rotina de inicialização é complexa. Toda a complexidade vai em um construtor que é chamado pelos demais.

Ao usar a sintaxe this() algumas regras de sintaxe devem ser observadas:

• A chamada para this() deve ser o primeiro comando do construtor

• Os parâmetros de this() devem casar com os parâmetros esperados por um construtor que não seja o chamador.

public class Produto { private String nome; public Produto() { this( “” ); } public Produto(String nome) { this.setNome( nome ); } }

Um construtor pode chamar outro construtor usando a sintaxe this()

Page 143: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Aprofundando o estudo sobre classes

5-12

Método destrutor – finalize()

Em algumas linguagens como C++, uma classe pode fornecer um destrutor. Um destrutor é similar a um construtor, sendo chamado automaticamente logo antes de o objeto ser destruído.

Um destrutor é normalmente empregado para liberar recursos mantidos pelo objeto, tais como memória secundária alocada, arquivos abertos, etc.

Java gerencia automaticamente a memória, logo um objeto não precisa explicitamente liberar memória que tenha alocado. Conseqüentemente, Java não suporta destrutores. A fim de permitir que um objeto libere outro recurso que não memória (pois esta já é automaticamente gerenciada), tais como arquivos abertos, Java permite que uma classe forneça um método finalize().

O método finalize() é chamado automaticamente quando um objeto é coletado pelo sistema coletor de lixo. Infelizmente, como vimos antes, não há como saber quando isto ocorrerá, ou mesmo que ocorrerá antes de o programa terminar.

A falta de previsibilidade de quando o método finalize() será chamado é inaceitável se os recursos são escassos.

A única solução é gerenciar tais recursos manualmente. A fim de assumir o controle do processo, você pode definir um método público dispose() em sua classe, que os usuários da classe terão de chamar quando tiverem terminado de usar um objeto desta classe.

Você pode ainda manter o método finalize() se quiser, como um último esforço de liberar os recursos.

Código 5-10: Método finalize para liberação de recursos alocados pela objeto.

public class Produto { public void finalize() { // Libera todos os recursos alocados pela classe System.out.println( "Instância sendo coletada pelo GC!" ); } }

Page 144: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Aprofundando o estudo sobre classes

5-13

Variáveis de instância

Variáveis de instância são definidas dentro do bloco de código da classe. As variáveis de instância são variáveis que irão guardar valores específicos para cada instância da classe. Normalmente definimos variáveis/atributos como sendo de instância. Pode-se chamar os atributos que declaramos até o momento como variáveis de instância. O padrão quando declaramos atributos é que os mesmos sejam de instância. Veja o exemplo abaixo: public class Cliente { /* Variáveis/atributos de instância */ private String codigo; private String nome; private char plano; /* Variável de classe */ public static float desconto; }

Código 5-11 : Declarando vaiáveis de instância Uma variável/atributo de instância pode ser acessado por um método de instância somente, ou pelo construtor da classe. Observe que no código acima termos três variáveis de instância e uma de classe declaradas no fonte. Cada variável de instância terá um valor específico para o atributo. Veja a figura abaixo: codigo = 98 codigo = 100 nome = Rafael nome = Walter plano = A plano = B obj01 obj02 Figura 5-1 : Objetos com variáveis de instância

Page 145: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Aprofundando o estudo sobre classes

5-14

O código que cria estes objetos é o seguinte: public class CriaCliente { public static void main(String[] args) { Cliente obj01 = new Cliente(); obj01.setCodigo(98) obj01.setNome(“Rafael”); obj01.setPlano(‘A’); Cliente obj02 = new Cliente(); obj02.setCodigo(100) obj02.setNome(“Walter”); obj02.setPlano(‘B’); } }

Código 5-12 : Criando objetos Cliente

Page 146: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Aprofundando o estudo sobre classes

5-15

Métodos de instância

De maneira análoga às variáveis de instâncias, você utiliza o operador ponto para chamar um método de instância de um objeto. A sintaxe é a

seguinte:

Código 5-13: Estrutura de chamada de um método de instância com parâmetros.

Se o método não espera nenhum argumento, você deve se lembrar apenas de colocar os parêntesis (uma lista vazia de parâmetros):

Código 5-14: Estrutura de chamada de um método de instância sem parâmetros.

No exemplo abaixo temos declaros na classe três métodos de instância. Observe estes e veja que os mesmos acessam os atributos de instância da classe. public class Cliente { /* Variáveis/atributos de instância */ private String codigo; private String nome; private char plano; /* Métodos de instância */ public void setCodigo(String codigo) { this.codigo = codigo } public String getCodigo() { return this.codigo; } public boolean validar() { ... } }

Código 5-15: Definindo métodos de instância

referenciaObjeto.nomeMetodo(parâmetros ...);

referenciaObjeto.nomeMetodo();

Page 147: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Aprofundando o estudo sobre classes

5-16

Variáveis de classe

Variáveis de classe são variáveis comparadas as variáveis globais. Estas ao serem definidas irão possuir o mesmo valor para todos os objetos da classe.

Uma variável de classe, também chamada variável estática (variável static), é aquela que pertence à classe e é comum a todas as instâncias desta classe. Em outras palavras, há somente uma instância de uma variável de classe, não importa quantas instâncias da classe existam.

Observe o código que declaramos na sessão anterior quando estávamos estudando variáveis de instância. Havia uma variável/atributo de classe. O código é o seguinte:

public class Cliente { /* Variáveis/atributos de instância */ private String codigo; private String nome; private char plano; /* Variável de classe */ public static float desconto; }

Código 5-16 : Variável de classe definida

Agora veja como seria o desconto para os objetos da classe:

codigo = 98 codigo = 100 nome = Rafael nome = Walter plano = A plano = B desconto = ... obj01 obj02 Figura 5-2 : Objetos compartilhando variável de classe

Page 148: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Aprofundando o estudo sobre classes

5-17

O desconte seria o mesmo para ambos os objetos. Em outras palavras podemos dizer que um atributo/variável de classe é compartilhado por todos os objetos da classe. Veja como ficaria o código para acesso a este atributo/variável:

public class CriaCliente { public static void main(String[] args) { Cliente.desconto = 5.4f; Cliente obj01 = new Cliente(); obj01.setCodigo(98) obj01.setNome(“Rafael”); obj01.setPlano(‘A’); Cliente obj02 = new Cliente(); obj02.setCodigo(100) obj02.setNome(“Walter”); obj02.setPlano(‘B’); } }

Código 5-17: Acessando variável de classe

Quando formos nos referencia a um atributo/variável de classe devemos utilizar o nome da classe para tal e não o nome do objeto. Neste exemplo estamos acessando diretamente o atributo, porém iremos mostrar mais adiante como deve ser feito o acesso a ele via uma operação.

Em Java variáveis de classe são declaradas usando a palavra reservada static. No exemplo abaixo, nós declaramos a variável de classe precoMinimo porque, obviamente, o preço mínimo se aplica a todas as instâncias da classe Produto.

Observe que precoMinimo foi declarada private, porque ela precisa ser acessada apenas pelos métodos da classe Filme. Neste exemplo, a variável precoMinimo é compartilhada por todos objetos, ou seja, é igual para todas as instâncias de Filme, muito embora cada instância possua sua própria descrição e código.

Código 5-18: Variáveis de classe

public class Produto { private static double precoMinimo; // var. de classe private String descricao; // var. de instância private int codigo; // var. de instância }

Page 149: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Aprofundando o estudo sobre classes

5-18

Figura 5-3: Variáveis de classe e variáveis de instância.

Page 150: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Aprofundando o estudo sobre classes

5-19

Inicializando Variáveis de Classe

Variáveis de classe são inicializadas quando a classe é carregada. Como construtores são utilizados para construir instâncias (e, portanto, invocados toda vez que uma nova instância é criada), você não pode utilizar construtores para inicializar variáveis de classe.

Variáveis de classe possuem os mesmos valores de inicialização default que as variáveis de instância (na verdade qualquer variável definida e não inicializada recebe um valor de inicialização default): inteiros recebem o valor 0, reais o valor 0.0, booleanos o valor false, caracteres o valor '\u0000' e referências o valor null.

Assim como as variáveis de instância, as variáveis de classe também podem ser inicializadas com valores diferentes do valor default. Basta, para isto, utilizar

inicializadores.

Código 5-19: Declaração de variáveis de classe

Rotinas complexas de inicialização de variáveis de classe devem ser colocadas no bloco de inicialização estático (também conhecido como inicializador estático).

Um inicializador estático não possui nome, nem valor de retorno e começa com a palavra reservada static seguida por um bloco de código delimitado por chaves (static {...}).

Funciona de maneira similar a um construtor, com a diferença de que é executado apenas uma única vez e não depende das variáveis de instância de uma classe (não pode sequer referenciá-las).

Código 5-20: Bloco static para inicialização de estruturas da classe

public class Produto { private static double precoMinimo = 30.50; private String nome = "CD"; private int codigo = 1234; ... }

public class Produto { private static double precoMinimo; static { Date dataAtual = new Date(); precoMinimo = getPrecoMinimoDia( dataAtual ); } }

Page 151: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Aprofundando o estudo sobre classes

5-20

Métodos de classe

Um método de classe, também conhecido como estático (método static) , é um método que pertence à classe e é compartilhado por todas as instância desta classe. Ao contrário de um método de instância, uma método de classe não atua sobre um único objeto. Estes métodos não recebem, portanto, a referência implícita this.

Um método de classe pode acessar somente variáveis de classe e invocar métodos de classe.

Métodos de classe são ideais para acessar variáveis de classe. De fato, eles são a única maneira, caso não exista nenhuma instância da classe (lembre-se: mesmo não existindo nenhuma instância de uma classe, as variáveis de classe já existem e têm um valor associado, pois são criadas quando a classe é carregada pelo ambiente de execução.

Não é necessário ter uma instância da classe criada para poder acessar variáveis de classe) No exemplo abaixo, o valor do preço mínimo é alterado para todos os produtos, mesmo que nenhum objeto produto tenha sido criado

ainda.

Código 5-21: Declaração de método de classe

Veja o código que usaria esta classe definida acima: public class TestaStatic { public static void main(String[] args) { Produto.setPrecoMinimo( 17.5 );

// ou Produto p1 = new Produto(); p1.setPrecoMinimo( 19.23 ); // Não recomendnado! } }

Código 5-22 : Acessando métodos de classe

Objetos de classe são chamados com a seguinte sintaxe:

Código 5-23: Estrutura de chamada de métodos de classe

public class Produto { private static double precoMinimo; public static void setPrecoMinimo( float precoMinimo ) { Produto.precoMinimo = precoMinimo; } }

NomeClasse.nomeMetodo(parametros);

Page 152: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Aprofundando o estudo sobre classes

5-21

Você pode chamar métodos de classe usando uma referência para um objeto e o operador ponto (da mesma maneira usada para métodos de instância), mas ainda assim, o método de classe só poderá acessar as variáveis de classe.

Page 153: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Aprofundando o estudo sobre classes

5-22

Exemplos de variáveis e métodos estáticos

Quando você executa uma aplicação Java, a JVM localiza e chama o método main() desta classe. Muito embora tudo em um programa Java deva estar definido dentro de uma classe, você não precisa criar uma instância da classe principal se main() chama apenas métodos de classe e manipula apenas

variáveis de classe.

Código 5-24: Exemplos de métodos estáticos.

Se, no entanto, main() acessa variáveis ou métodos de instância da própria classe em que se encontra definido, é necessário, antes de mais que ele crie instâncias desta classe.

A classe Math fornece métodos de classe para o cálculo de muitas funções matemáticas, tais como funções trigonométricas e logaritmos.

Fornece também várias constantes de classe tais como e (2.71828) e π (3.1415926).

A classe System fornece vários métodos de classe que representam o estado de todo o sistema (ambiente computacional). System.out é uma variável de classe que se refere ao objeto PrintStream.

Esta variável de classe representa a saída padrão de dados. println() é um método de instância de PrintStream.

public class ApenasMetodosEstaticos { public static void main( String args[] ) { double num, raiz; // ... raiz = Math.sqrt( num ); // Usando uma biblioteca System.out.println("A raiz de " + num + " é " + raiz); }

Page 154: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Aprofundando o estudo sobre classes

5-23

O mecanismo de herança entre classes

Herança define uma relação entre classes, onde uma classe (subclasse) toma de empréstimo as estruturas de dados e os comportamentos de outra classe (superclasse).

Herança é uma valiosa técnica porque estimula e possibilita a reutilização de software ao permitir criar uma nova classe baseada nas propriedades de uma classe existente. Como resultado, o desenvolvedor é capaz de alcançar grande produtividade que, de outra forma, seria impossível.

Construtores são blocos de código executados quando um objeto de uma classe é criado. Já vimos isto anteriormente. Ao usar o modelo de herança, cada subclasse tem acesso ao construtor da superclasse. Qualquer código comum relativo a inicialização do objeto, pode ser colocado na superclasse e invocado pela subclasse.

Esta técnica minimiza a necessidade de se duplicar código e garante consistência na criação de objetos.

Polimorfismo descreve a capacidade de Java executar um método específico com base na referência a um objeto utilizada na chamada. Usando esta técnica, você pode definir um método na superclasse e sobrescrevê-lo na subclasse apropriada.

Você pode invocar os métodos da superclasse e, caso o método tenha sido sobrescrito na subclasse, Java automaticamente chamará o método apropriado. Isto é uma construção muito poderosa que possibilita definir métodos na superclasse sem mesmo conhecer detalhes de qualquer subclasse específica.

Somente use herança para modelar uma genuína relação “é um tipo de”. Em outras palavras, não use herança senão quando todos os métodos herdados se aplicam à subclasse.

Se você não pode substituir um objeto da superclasse por um objeto da subclasse, então você não tem uma genuína relação “é um tipo de”. Neste caso, as classes podem se relacionar, mas não hierarquicamente.

Se você realmente usa herança, deve explorar a natureza polimórfica dos métodos de instância na hierarquia de classes. Por exemplo, se você acha que deve testar o tipo de um objeto na árvore de herança, use polimorfismo para evitar ter de escrever código separado para tratar objetos de cada classe. Isto maximiza a reutilização de seu código, e o torna mais fácil de manter no futuro.

Vamos agora ver como estes conceitos mostrados acima são aplicados em java

Page 155: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Aprofundando o estudo sobre classes

5-24

Herdando estrutura e comportamento

Uma relação de herança faz com que a classe filha herde toda a estrutura e comportamento dos pais.

A classe Produto define os atributos e métodos que são relevantes para todos os itens de inventário. Entre os atributos e métodos prováveis:

• Atributos tais como data de aquisição, custo de aquisição, e condição.

• Métodos tais como cálculo de quantia a ser paga pelo item, mudança de condições, e definição de preço.

Dependendo do que quiser fazer no programa, você precisará definir um tipo específico de Produto. Você pode usar herança para definir uma subclasse de itens de inventário para cada tipo distinto de item.

Você poderia definir, por exemplo, as seguintes subclasses: CD, DVD e VHS.

Cada uma destas subclasses automaticamente herdaria todos os atributos e métodos de Produto e atributos e métodos adicionais poderiam ser fornecidos se necessários.

A classe CD, por exemplo, poderia definir os seguintes atributos e métodos adicionais:

• Atributos tais como título, produtor, duração.

• Métodos tais como play, stop, etc.

Subclasses podem também sobrescrever métodos da superclasse se desejarem fornecer um comportamento mais especializado para o método.

Figura 5-4: Herança entre Produto e CD.

Page 156: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Aprofundando o estudo sobre classes

5-25

Especificando herança em Java

Quando você define uma subclasse, você precisa somente fornecer código para as facilidades da subclasse que diferem das existentes na superclasse. Efetivamente, a subclasse apenas estende a superclasse.

A sintaxe para especificar herança em Java faz uso da palavra reservada extends.

Por exemplo:

Código 5-25: Especificando herança em Java.

Se você tem experiência com outras linguagens OO (orientada por objetos) tais como C++, observe que Java permite somente herança simples.

Em outras palavras, uma classe pode especificar somente uma única superclasse da qual herda.

Lembre-se também que todas as classes em Java herdam automaticamente de uma classe raiz conhecida como Object, que se situa sempre no topo da árvore de herança.

Se uma classe não especifica explicitamente uma superclasse, como no caso de Produto, então esta classe é forçada a herdar diretamente de Object, sendo sua definição (implícita) equivalente à seguinte definição explícita:

Código 5-26: Utilizando a cláusula extends.

public class Produto extends Object { // Definição da classe Produto } public class CD extends Produto { // Métodos e atributos adicionais para distingui-la // dos outros tipos de itens de produto }

public class Produto extends Object { // Definição da classe Produto }

Page 157: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Aprofundando o estudo sobre classes

5-26

Objetos de subclasses

A superclasse define as variáveis que são relevantes para todos os tipos de Produto, tais como nome e codigo. A subclasse CD herda estas variáveis sem ter de fazer qualquer esforço, e precisa somente especificar as variáveis que lhe são específicas, tais como duração.

Suponha as seguintes classes:

Figura 5-5: Herança entre as classes CD e Produto.

Se você cria um objeto Produto, ele apenas contém as variáveis definidas para Produto:

Código 5-27: Criando um novo Produto.

Entretanto, se você cria um objeto CD, ele conterá cinco variáveis de instância: as três herdadas de Produto mais as duas que ele próprio CD definiu.

Código 5-28: Criando um novo CD

Variáveis de instância devem normalmente ser declaradas private, o que significa que instâncias de subclasses herdam os valores, mas não podem acessá-los diretamente.

Como visto anteriormente, você deve definir, métodos para acessar variáveis privadas. Você pode definir métodos na subclasse ou herdá-los da superclasse.

Produto produto = new Produto();

CD cd = new CD();

Page 158: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Aprofundando o estudo sobre classes

5-27

Chamando construtores da superclasse

A superclasse e a subclasse geralmente terão construtores que esperam parâmetros. Suponha, por exemplo, que Produto tenha um construtor que espera como parâmetros os valores iniciais de preco, nome e codigo.

Da mesma forma, a classe CD tem um construtor que espera parâmetros suficientes para inicializar seus atributos. As coisas aqui começam a ficar interessantes.Um objeto CD tem cinco atributos: preco, nome e codigo herdados de Produto, e produtor e duracao definidos na própria classe CD.

O construtor de CD terá, portanto, cinco argumentos:

Código 5-29: Utilizando o contrutor de CD com parâmetros.

Ao invés de inicializar preco, nome e codigo explicitamente, tudo o que o construtor de CD deve fazer é chamar o construtor de sua superclasse. Isto pode ser feito usando a palavra reservada super. A chamada super(...) deve ser o primeiro comando do construtor.

Código 5-30: Invocando o construtor da superclasse a partir da referência super.

Se você não chamar explicitamente super(...) o compilador chamará automaticamente o construtor sem parâmetros. Se a superclasse não tiver um construtor sem parâmetros, o compilador acusará um erro.

public CD(float preco, String nome, int codigo, String produtor, int duracao)

public CD(float preco, String nome, int codigo, String produtor, int duracao) { super( preco, nome, codigo ); setProdutor( produtor ); seDuracao( duracao ); }

public Produto(float preco, String nome, int codigo) { setPreco( preco ); setNome( nome ); setCodigo( codigo ); }

public CD(float preco, String nome, int codigo, String produtor, int duracao) { super( preco, nome, codigo ); setProdutor( produtor ); seDuracao( duracao ); }

Page 159: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Aprofundando o estudo sobre classes

5-28

Código 5-31: Referenciando o construtor da superclasse.

Page 160: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Aprofundando o estudo sobre classes

5-29

Overloading e Overriding de métodos

Overloading e overriding são freqüentes na programação orientada a objetos. Overloading é conhecido como sobrecarga enquanto overriding é conhecido como sobreescrita. Vejamos abaixo a definição destes dois conceitos:

• Sobrecarga de métodos é quando você define múltiplos métodos com mesmo nome e diferentes assinaturas. Métodos sobrecarregados são resolvidos em tempo de compilação (resolver um método é descobrir qual versão do método deve ser chamada com base nas informações dadas pelo programador), com base no número e tipo dos parâmetros fornecidos.

• Sobrescrita de métodos é quando você fornece um método com exatamente o mesmo nome e assinatura que este método possui em uma superclasse. Métodos sobrescritos são resolvidos em tempo de execução. Esta técnica é conhecida como polimorfismo e será discutida mais adiante.

Page 161: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Aprofundando o estudo sobre classes

5-30

Redefinindo métodos – overriding

Quando uma classe herda operações de outra classe, estas operações passam a fazer parte da estrutura da classe filha. Nem sempre desejamos manter a mesma implementação para a operação nos filhos, desta forma podemos redefinir tal operação. Vejamos os códigos de exemplo abaixo:

Código 5-32: Especificando métodos adicionais na subclasse.

O exemplo acima mostra alguns dos métodos declarados pela subclasse e pela superclasse.

A superclasse define métodos que são relevantes para todos os tipos de Produto.

A subclasse CD herda estes métodos da superclasse, e tem de adicionar apenas os métodos que lhe são específicos (relevantes para todos os objetos CD), tais como recuperação do produtor do CD e duração.

Quando você cria um objeto, você pode chamar qualquer um dos seus métodos públicos (public), bem como qualquer método declarado público em uma de suas superclasses.

Se você, por exemplo, cria um objeto Produto, você pode chamar os métodos públicos definidos em Produto, bem como quaisquer métodos públicos de sua superclasse Object:

Código 5-33: Criando um Produto e acessando métodos herdados.

public class Produto { public float getPreco(); public String getNome(); }

public class CD extends Produto { public int getDuracao(); public String getProdutor(); }

Produto produto = new Produto(); float preco = produto.getPreco(); // método public de Produto Class classe = produto.getClass(); // método public de Object

Page 162: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Aprofundando o estudo sobre classes

5-31

Se você cria um objeto CD, você pode chamar métodos públicos definidos em CD, Produto e Object.

Código 5-34: Criando um CD e acessando métodos herdados

Sobrescrevendo métodos da superclasse

Uma subclasse herda todos os métodos de sua superclasse. Uma subclasse pode modificar o comportamento de um método de sua superclasse sobrescrevendo-o, como mostra o exemplo abaixo:

Código 5-35: Sobreescrevendo o método getPreco()

Para sobrescrever um método de uma superclasse, a subclasse define o método exatamente com a mesma assinatura e tipo de retorno que o método possui quando declarado na superclasse.

O método da subclasse efetivamente esconde o método declarado na superclasse. É importante ter certeza de que o método na subclasse mantém a mesma semântica que o método que está sendo sobrescrito.

Qual método é chamado? No exemplo acima, a classe Produto fornece um método getPreco() e a classe CD sobrescreve este método com uma versão mais especializada.

Se você criar um objeto Produto e chamar getPreco(), o método chamado será a versão definida em Produto.

CD cd = new CD(); int duracao = cd.getDuracao() // método public de CD float preco = cd.getPreco(); // método public de Produto Class classe = cd.getClass(); // método public de Object

public class Produto { public float getPreco() { return preco; } }

public class CD extends Produto { public float getPreco() { float x = getCustoCD() + calculaImpostos(); return x; } }

Page 163: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Aprofundando o estudo sobre classes

5-32

Se você criar um objeto CD e chamar getPreco(), o método chamado será a versão especializada definida em CD.

Page 164: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Aprofundando o estudo sobre classes

5-33

Referência super

A referência super é útil quando a classe possui um ancestral. Uma subclasse herda todos os métodos e variáveis de sua superclasse, bem como define ela própria. Métodos da superclasse podem ser sobrescritos na subclasse, bastando a subclasse declará-los novamente e redefinir o seu comportamento (declarar novamente significa manter a assinatura do método tal qual se encontra na superclasse alterando apenas o corpo do método).

A palavra reservada super permite que você acesse métodos da superclasse sobrescritos pela subclasse.

Um dos usos mais comuns de super é chamar os construtores da classe pai. Quando a superclasse foi projetada, um construtor provavelmente foi declarado para garantir a inicialização correta de qualquer novo objeto. Como a subclasse herda todas as variáveis da superclasse, tais variáveis precisarão ser inicializadas para objetos da subclasse também. A palavra reservada super permite que você use o código do construtor definido na superclasse sem ter que duplicar o código em cada subclasse.

Adicione a referência super no construtor da subclasse a fim de acessar o

construtor da superclasse:

Código 5-36: Estrutura de chamada explícita do construtor da superclasse

A regra de sintaxe é que a palavra reservada super deve ser, neste caso, a primeira linha do construtor da subclasse. A palavra reservada super pode ser usada também para acessar os métodos da superclasse.

Exemplo de uso da referência super:

class SubClasse extends SuperClasse { ... public SubClasse(int param) { super(param); /* coloque aqui o código específico do construtor da subclasse */ } }

public class Produto { private String nome; public Produto( String nome ) { super(); this.nome = nome; } }

Page 165: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Aprofundando o estudo sobre classes

5-34

public class Filme extends Produto { private int ano; public Filme( String nome, int ano ) { super( nome ); this.ano = ano; }

Código 5-37: Referência super invocando o construtor da superclasse

No exemplo acima, há rotinas de inicialização que devem ocorrer para todos os objetos Produto. Estas rotinas são colocadas nos construtores de Produto. Tais rotinas devem sempre ser usadas, não interessando o tipo do Produto sendo construído, seja ele um CD, um Filme ou um Livro (subclasses de Produto).

Há também construtores em cada uma das subclasses encarregados de rotinas de inicialização específicas destas subclasses.

O construtor de Filme reutiliza o construtor de Produto ao referenciá-lo com a palavra reservada super. Este comando é o primeiro comando do construtor de Filme e pode ser seguido por quaisquer comandos que se fizerem necessários para uma adequada inicialização de objetos Filme.

Page 166: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Aprofundando o estudo sobre classes

5-35

Invocando métodos da superclasse

Como mencionado anteriormente, quando uma subclasse sobrescreve um método de sua superclasse, ela esconde o método da superclasse.

Código 5-38: Sobreescrevendo e invocando o método getPreco()

Se, por exemplo, o programa criar um objeto CD e chamar o método getPreco(), ele sempre estará executando a versão de getpreco() definida

em CD.

Código 5-39: Executando o método getPreco()

Dentro do método getPreco() definido na classe CD pode-se invocar o método escondido de mesmo nome e assinatura, definido na superclasse Produto, através da palavra reservada super.

A palavra reservada super é similar a this, salvo que atua como referência para o objeto corrente como uma instância da superclasse.

Chamar um método escondido da superclasse usando super evitamos duplicar o código contido no método escondido. Ao reduzir o volume de código duplicado, facilita-se a tarefa de manutenção do software.

public class Produto { public float getPreco() { return preco; } }

public class CD extends Produto { public float getPreco() { return super.getPreco() + calculaImpostos(); } }

CD cd = new CD(); // Cria objeto CD float v = cd.getPreco(); // Executa versão getPreco() de CD

Page 167: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Aprofundando o estudo sobre classes

5-36

Visibilidade protected

A visibilidade protected não foi demonstrada anteriormente pois o uso da mesma envolve o processo de herança. Agora que já vimos este recurso estamos aptos a estudar esta visibilidade. Vejamos o código abaixo: package com.targettrust.java; public class Funcionario { private String nome; protected float salario; ... }

Código 5-40: Visiblidade protected aplicada a atributos

O código acima define uma classe Funcionário, a qual possui na sua estrutura um nome e um salário. Perceba que o nome é privado enquanto o salário é protected. O atributo nome poderá ser acessado somente por operações definidas dentro da classe, porém o atributo salário poderá ser acessado diretamente por outras classes que forem filhas de Funcionario. Isto poderá ser feito mesmo com a classe filha em outro pacote diferente do pacote onde estiver o Funcionário. Veja exemplo abaixo: package com.targettrust.rh; public class Vendedor extends Funcionario { private float comisssao; ... public void calcularSalario() { ... float total = salario + comissao; } }

Código 5-41: Acessando um atributo protected Veja que o acesso ao atributo é acessado na classe filha como se fosse declarado na mesma classe. Já o atributo privado não pode ser acessado. Esta visibilidade também pode ser aplicada a operações da classe, porém o uso dela nestes casos não é comum.

Page 168: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Aprofundando o estudo sobre classes

5-37

Varargs

Varargs é um recurso popular em algumas linguagens como C, C++ e

linguagens derivadas. Este recurso permite passar um número variável de parâmetros a um método sem a necessidade de encapsulá-los manualmente em um array. Junto com varargs será utilizado o recurso de autoboxing. Veja o exemplo abaixo utilizando este recurso:

public class Varargs { public static void main(String[] args) { foo("Java", "Oracle", "Linux"); foo("Porto Alegre", "Ijui", "São Leopoldo", "Cruz Alta"); } public static void foo(String... args) { for (int i=0; i<args.length; i++) { System.out.println(args[i]); } } }

Código 5-42: Usando varargs para receber mais de um parâmetro A declaração acima “String... args” equivale a “String[] args”, mas se utilizado este recurso deve ser o último parâmetro do método. Quando este método for chamado na chamada podem ser passados vários parâmetros separados por vírgula desde que os tipos sejam sempre Strings. O enpasulamento dos parâmetros String em um vetor será feito de forma automática pelo compilador. Se o tipo de parâmetro é um Object, então os parâmetros se forem tipos primitivos serão transformados em objetos com o recurso de autoboxing. Para evitar este overhead da transformação de tipos primitivos nos objetos correspondentes utilizando o recurso de autoboxing, você pode utilizar, por exemplo “int... args”. Se você tentar passar parâmetros com tipo incorretos, portanto não esperados pelo método, o compilador irá perceber e avisar. Veja exemplo abaixo: public class Varargs { public static void main(String[] args) { foo("Java", "Oracle", "Linux", 88); // Erro nesta linha! } public static void foo(String... args) { for (int i=0; i<args.length; i++) { System.out.println(args[i]); } } }

Page 169: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Aprofundando o estudo sobre classes

5-38

Código 5-43: Erro pois esta pasando inteiro e não String

Page 170: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Aprofundando o estudo sobre classes

5-39

Polimorfismo

Usando a técnica de polimorfismo visualize a seguinte hierarquia de classes.

Figura 5-6: Hierarquia de classes representando herança e polimorfismo do método getPreco().

Ao projetar a aplicação de venda, não era sabido todo o tipo de produtos que seriam vendidos em longo prazo. Em programação não orientada por objetos, isto criaria um problema, que seria resolvido alterando o código sempre que um novo tipo de item fosse adicionado. Em Java, nós podemos usar polimorfismo para resolver este problema. Eis como:

O método getPreco() da classe Produto é sobrescrito pelas classes CD e DVD, cada qual fornecendo uma versão especializada do método.

A classe CarrinhoCompras possui um método addItem(Produto

produto) que chama o método getPreco() através da referência recebida a um objeto Produto.

Em tempo de execução Java interroga o parâmetro de addItem() para descobrir o tipo real do objeto e se o objeto possui alguma função sobrescrita. Se sim, Java usa o método sobrescrito pela subclasse (CD ou DVD), ao invés de usar o método definido pela superclasse (Produto).

Page 171: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Aprofundando o estudo sobre classes

5-40

Por exemplo, se a variável cd do tipo CD e dvd do tipo DVD forem adicionadas:

Código 5-44: Adicionando CD e DVD ao método que espera Produtos.

O mais importante é que as classes CarrinhoCompras e Produto não precisam ser modificadas quando novos tipos de itens de inventários forem sendo adicionados ao negócio.

addItem(cd); // O método addItem chamará a versão de getPreco // definida em CD e não em Produto addItem(dvd); // O método addItem chamará a versão de getPreco // definida em DVD e não em Produto

Page 172: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Aprofundando o estudo sobre classes

5-41

Modificador final

Por default todas as variáveis e métodos podem ser sobrescritos. Especificar uma variável como final evita que seu valor seja alterado. Isto é útil para garantir que um determinado valor seja consistente entre todos os usuários de uma classe.

Você pode também declarar uma classe como final. Uma classe final não pode ser superclasse de nenhuma outra classe. Em outras palavras, não se pode herdar de uma classe final.

Ao declarar uma classe como final você está tomando uma importante decisão de projeto, pois está dizendo que tal classe é completa o suficiente para atender todas as expectativas presentes e futuras de seus usuários, e que, portanto, nunca será necessário estendê-la para fornecer alguma funcionalidade adicional.

Um método final não pode ser sobrescrito por nenhuma subclasse. Em outras palavras, se o programador herda de uma classe, não será permitido que ele forneça uma versão alternativa de um método declarado como final na superclasse.

Esta é uma técnica útil para evitar que programadores inadvertidamente ou maliciosamente redefinam métodos essenciais que devem funcionar de uma maneira esperada.

Resumindo:

• Uma variável final é uma constante

• Uma variável final não pode ser modificada

• Uma variável final deve ser inicializada

• Uma variável final é geralmente pública (public), permitindo o acesso externo

Código 5-45: Variáveis final

Métodos e classes são declarados final por suas razões principais: segurança e otimização.

public final class Color { public final static Color BLACK = new Color(0,0,0); // ... }

Page 173: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Aprofundando o estudo sobre classes

5-42

Se um método executa alguma operação vital, tal como validação de identidade ou verificação de autorização, ele deve ser declarado final, a fim de evitar que seja sobrescrito por um método mal-intencionado que esteja procurando se esquivar das verificações de segurança.

Muitos dos métodos definidos nas classes do pacote java.net são declaradas final.

Se você declara uma classe como final, ela não poderá nunca mais ser estendida por nenhuma outra classe. Esta é uma decisão de projeto importante, pois afirma que a classe atende a todas as necessidades presentes e futuras de seus usuários. Esta implicação é clara: você não precisa.

Código 5-46: Definindo uma Classe e um método final.

public final class Criptografia{ private String senha; public final void getSenha(String senha) { getCriptografia(senha, 128) // Chama Criptografia de 128 bits } }

Page 174: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Aprofundando o estudo sobre classes

5-43

Enums

Enums é uma forma mais fácil e segura para representar um conjunto de

valores que são conhecidos em tempo de compilação e que não mudam com o passar do tempo. Estes valores são muitas vezes conhecidos como constantes de classe. A partir da nova versão do java, a versão 1.5, foi incluído este novo tipo que trás algumas vantagens listadas abaixo. Veja inicialmente o padrão que se costuma utilizar para representar constantes e guardar estações do ano:

public static final int ESTACAO_INVERNO = 0; public static final int ESTACAO_PRIMAVERA = 1; public static final int ESTACAO_VERAO = 2; public static final int ESTACAO_OUTONO = 3;

Código 5-47: Constantes de classe Este padrão tem os seguintes problemas:

• Não é seguro – Uma vez que uma estação é um int, você pode passar qualqeur outro valor diferente dos especificados nas constantes acima, ou mesmo somar estas constantes, o que não faria sentido.

• Prefixar constantes – Você precisa prefixar as constantes com strings para evitar colisões de nomes semelhantes. Este caso foram prefixadas com a palavra ESTACAO.

• Os valores impressos não são informativos – Por serem constantes do tipo int estas constantes quando impressas não tem significado claro. Ao imprimi-la teremos um int e não um nome.

Com enums o mesmo código acima ficaria da seguinte maneira:

enum Estacao { INVERNO, PRIMAVERA, VERAO, OUTONO }

Código 5-48: Definindo uma enumeration

Tipos enum são cosiderados como objetos, acima temos a definição de um tipo “Estacao”. Uma enumeration herda da classe java.lang.Enum possuindo desta forma vários métodos para se poder manipular a estrutura. Métodos de Object também estão presentes em uma Enum. Comparable e Serializable são interfaces implementadas pelas enumerations, permitindo que as mesmas portanto possam ser comparadas e serializadas.

Page 175: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Aprofundando o estudo sobre classes

5-44

Veja abaixo uma versão completa de um código que utiliza enumerations:

enum Estacao { INVERNO, PRIMAVERA, VERAO, OUTONO } public static void main(String[] args) { foo( Estacao.INVERNO ); } public static void foo(Estacao x) { out.println( x.ordinal() +" "+ x.name() ); // 0 INVERNO } Código 5-49: Usando uma enumeration Neste código acima observe que definimos um tipo “Estacao” e o mesmo é utilizado mais abaixo para passar valores ao método foo. Quando desejarmos imprimir o nome da estação passada como parâmetro através de enum podemos utilizar o método name(), a ordem dos valores é adicionada de forma automática e começa em 0. É possível pegar de uma enumeration todos os seus valores através de um método estático values(). Este método facilita bastante a impressão dos valores quando desejarmos. Veja o código abaixo: for(Estacao s : Estacao.values() ) { out.println( s.name() + " " +s.ordinal() ); }

Código 5-50: Percorrendo uma enumeration

Page 176: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Aprofundando o estudo sobre classes

5-45

Espaço para anotações

Page 177: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Aprofundando o estudo sobre classes

5-46

Exercícios

1. Neste exercício você deve criar uma classe para representar um Curso. Esta classe terá métodos sobrecarregados (overloading) e redefinidos (overriding), bem como será uma classe filha da classe Produto e terá construtores para que seja possível criar objetos da mesma já passando informações na hora da criação. Passo 1: Crie uma classe pública Curso no pacode com.targettrust.venda e faça com que esta classe extenda (herde) a classe Produto. Na classe Curso defina os seguines atributos e constante privados: private int cargaHoraria; private char turno; private final float VALOR_HORA = 100f;

Passo 2: Defina na classe Curso um método para calcular o preço do curso

( public float getPreco() {...} ). Observe que este tem o mesmo nome do método que está sendo herdado da classe Produto. Na assinatura deste faça com que o mesmo possa receber um valor hora ( public float getPreco(float valorHora) {...} ) a ser levado em consideração no cálculo do preço do curso. O preço do curso deve ser calculado multiplicando-se a carga horária pelo valor hora passado como parâmetro no método.

Passo 3: Crie outro método na classe Curso que seja capaz de redefinir o comportamento (overriding) do método public float getPreco() herdado da classe Produto. Esta operação deve retornar o preço levando em consideração o valor hora e a carga horária do curso, para isto utilize o valor hora da constante.

Passo 4: Na classe Produto, bem como na classe Curso, defina um

construtor que permita criar um objeto destas classes passando valores para todos os seus atributos. Isto irá fazer com que o construtor default não seja adicionado pelo compilador java. Desta forma adicione também ele a estas classes.

Passo 5: No construtor da classe Curso faça com que o mesmo repasse os

parâmetros que este receber e que devem ser atribuídos para os atributos da classe Produto para o construtor da classe Produto. Use para isto a referência super(...).

Passo 6: Agora você irá modificar as classes que criou até o momento para

que as operações set’s da classe Produto, ItemPedido e Curso possam receber parâmetros com o mesmo nome dos atributos. Use a referência this nestas classes para referenciar o atributo na hora da atribuição e defina o nome do parâmetro

Page 178: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Aprofundando o estudo sobre classes

5-47

com o mesmo nome do atributo. Gere novamente a documentação para estas classes e verifique as alterações.

Passo 7: Na classe Curso defina o método destrutor finalize() e dentro deste

faça a impressão de uma string sinalizando que o mesmo está sendo executado.

public void finalize() { ... } Passo 8: Crie agora uma classe pública TestaCurso no pacote

com.targettrust.venda, declare nesta classe o método main e dentro deste método crie um objeto da classe Curso. Atribua informações para este objeto através do método construtor. Logo em seguida mostre os dados do objeto através dos seus métodos de leitura, os get’s.

Passo 9: Atribua null para a referência criada que representa o curso e logo

em seguida chame o método System.gc() para ativar o coletor de lixo e constatar a execução do método destrutor.

Passo 10: Na classe Curso crie um bloco estático de código para sinalizar quando a classe está sendo carregada pela JVM. Neste bloco estático imprima uma mensagem.

Page 179: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Java Fundamentals

6-1

66.. CCoolleeççõõeess,, AArrrraayyss,, SSttrriinnggss,, ee WWrraappppeerr CCllaasssseess

Page 180: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Coleções, Arrays, String e Wrapper Classes

6-2

Objetivos

• Estudar a API Collection

• Utilizar classes StringBuffer e StringBuilder

• Converter e encapsular dados com Wrapper Classes

• Utilizar arrays

• Compreender o mecanismo de autoboxing

• Utilizar generics

Page 181: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Coleções, Arrays, String e Wrapper Classes

6-3

Strings

Assim como na maioria das linguagens de programação, strings são usadas intensivamente em Java. Desta forma, a API Java fornece uma classe String para ajudá-lo a manipular seqüências de caracteres.

Literais de string são transformados pelo compilador Java em objetos String. Eles podem então ser usados diretamente, passados como argumentos para métodos ou atribuídos a variáveis do tipo String.

Código 6-1: Manipulação de Strings.

A classe String representa uma string imutável.

Isto significa que, uma vez criado um objeto String, você não poderá mais alterá-lo. Se você quiser modificar o conteúdo de uma string, você deverá usar a classe StringBuffer. Esta classe será estudada logo adiante.

System.out.println( "Hello World!" ); String str = "Matrix";

Page 182: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Coleções, Arrays, String e Wrapper Classes

6-4

Criando Strings

A maneira mais fácil de se criar uma string é a partir de uma constante colocada entre aspas duplas, como mostra o exemplo abaixo:

Código 6-2: Atribuição de valor String.

Você pode usar o operador mais (+) para concatenar dois objetos String. Isto é explicado em maiores detalhes adiante. Veja um exemplo do uso do operador mais (+) quando aplicado a objetos String:

Código 6-3: Concatenação de Strings entre variáveis e String fixa.

A classe String fornece vários construtores. Eis aqui alguns dos construtores mais úteis:

• String() cria uma string vazia, com o valor ""

• String(String str) cria uma cópia do objeto String referenciado por str

• String(char[] arr) cria uma string a partir dos caracteres presentes no vetor arr

Código 6-4: Criação de String utilizando o construtor da classe String.

Você encontrará uma lista de construtores na documentação do JDK para a classe String. A classe String é parte do pacote java.lang.

java.lang é um pacote automaticamente importado por todas as classes Java. Não é preciso, portanto, declarar um comando explícito de import para poder usar a classe String em seu código.

String produto = "Caneta";

String nomeEmp = primeiroNome + " " + ultimoNome;

// uso de construtores String nomeEmp = new String( "Maria Isabel" );

Page 183: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Coleções, Arrays, String e Wrapper Classes

6-5

Concatenando Strings

Java usa o operador + para concatenação de strings. O método concat() de String é outra forma de se concatenar strings.

O seguinte código produz strings equivalentes:

Código 6-5: Exemplos de concatenação de Strings.

O exemplo abaixo mostra um tipo primitivo (no caso um int) sendo concatenado com uma String.

O tipo primitivo é convertido implicitamente para String:

Código 6-6: Conversão de tipos primitivos para String.

Literais de string não podem se estender por mais de uma linha, mas você pode concatená-los e produzir o mesmo efeito:

Código 6-7: Concatenação de Strings utilizando caracteres de escape.

// Concatenação String nome = "Carlos Silva"; nome = "Carlos " + "Silva"; nome = "Carlos ".concat("Silva");

int codigo = getCodigo(); System.out.println("Código: " + getCodigo() + ".");

String soneto = "De tudo ao meu amor serei atento\n" + "Antes e com tal zelo, e sempre, e tanto\n" + "Que mesmo em face de maior encanto\n" + "Dele se encante mais meu pensamento.";

Page 184: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Coleções, Arrays, String e Wrapper Classes

6-6

Executando operações em objetos String

O método length() retorna o número de caracteres de uma string:

Código 6-8: Tamanho de uma String.

O método charAt() retorna o caractere especificado pelo índice passado como argumento para o método (os índices sempre começam em 0).

Código 6-9: Recebendo um caracter a partir de uma String.

O método substring() retorna uma substring específica (dois argumentos são fornecidos a este método: o índice do primeiro caractere da substring e o índice do caractere após o último caractere da substring desejada).

Código 6-10: Produzindo substrings.

O método toUpperCase() retorna uma nova string contendo uma versão da anterior com todos os caracteres convertidos para a forma maiúscula. O método toLowerCase() retorna uma nova string contendo uma versão da anterior com todos os caracteres convertidos para a forma minúscula.

Código 6-11: Transformando uma String para maiúsculo e minúsculo.

O método trim() retorna uma nova string contendo uma cópia da string original com espaços em branco removidos tanto no início quanto no final.

Código 6-12: Truncando espaços de uma String.

String s = "Maria"; int tam = s.length(); // tam = 5

// 01234 String s = "Maria"; char c = s.charAt(2); // c = 'r'

// 01234 String s = "Maria"; String sub = s.substring(2,4); // sub = "ri" String sub = s.substring(2); // sub = "ria"

String s = "Maria"; String M = s.toUpperCase(); // M = "MARIA" String m = s.toLowerCase(); // m = "maria"

String s = " Cadastro de Clientes "; String t = s.trim(); // t = "Cadastro de Clientes"

Page 185: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Coleções, Arrays, String e Wrapper Classes

6-7

O método indexOf() retorna o índice de uma determinada substring. O método lastIndexOf() retorna o índice da última ocorrência de uma string determinada.

Código 6-13: Busca índices de ocorrências de substring dentro de uma String.

Há várias versões para cada um destes métodos. Dê uma olhada na documentação da classe String para maiores detalhes sobre cada uma delas.

// 0 1 2 // 012345678901234567890 String s = "fábrica de brinquedos"; int iof = s.indexOf("bri"); // iof = 2 int liof = s.lastIndexOf("bri"); // liof = 11

Page 186: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Coleções, Arrays, String e Wrapper Classes

6-8

Comparando duas Strings

O método equals() retorna true se as strings especificadas contêm o mesmo texto. Caso a string passada como parâmetro seja null, equals() retorna false.

Importante: o método equals() diferencia maiúsculas de minúsculas!

Código 6-14: Comparação de Strings case sensitive.

O método equalsIgnoreCase() é similar a equals(), exceto que ignora diferença entre maiúsculas e minúsculas.

Código 6-15: Comparação de Strings case insensitive.

Não use o operador == para comparar objetos String! O operador == retorna true dependendo da JVM quando ambas as variáveis referenciarem o mesmo objeto.

String senha = getSenha(); if(senha.equals("brasil2010"))

String cat = getCategoria(); if(cat.equalsIgnoreCase("Drama"))

Page 187: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Coleções, Arrays, String e Wrapper Classes

6-9

Obtendo strings a partir de objetos

Se sua classe tem um método toString(), você pode incluir o seu objeto em expressões de concatenação de strings. E você pode imprimir seu objeto como se este fosse uma string. O método toString() é invocado automaticamente sempre que você usa um objeto em uma expressão de concatenação de strings ou passa este objeto para System.out.println().

No exemplo abaixo, a classe Produto fornece uma implementação de toString() que imprime o nome e o código do produto.

Código 6-16: Produzindo String a partir de uma referência.

O que acontece quando a classe não fornece o método toString()? Se a classe não fornece o método toString(), ela herda um da classe Object.

A string produzida por Object.toString() não é muito amigável. Consiste do nome da classe da qual o objeto é uma instância e um número hexadecimal representando uma entrada hash.

public class Produto { public String toString() { return getCodigo() + " - " + getNome(); } } ... Produto p1 = new Produto( 1, "DVD" ); System.out.println( "Produto: " + p1 ); // "1 – DVD"

Page 188: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Coleções, Arrays, String e Wrapper Classes

6-10

Convertendo tipos primitivos em strings

A classe String fornece um método estático valueOf() que retorna uma string representando o tipo primitivo. Há uma versão de valueOf() para cada tipo primitivo.

O exemplo abaixo usa duas versões:

Código 6-17: Convertendo tipos primitivos em String.

Quando um tipo primitivo é concatenado com uma string, ele é automaticamente convertido para String através de String.valueOf().

Quando um tipo primitivo é passado para System.out.println(), a versão apropriada de System.out.println() é chamada. Há uma versão para cada tipo primitivo.

Na versão do J2SDK 1.5 é permitido a seguinte codificação:

Código 6-18: Convertendo tipos primitivos em String utilizando printf no J2DSK 1.5.

As expressões “%s” e “%d” formatam as saídas de “James Gosling” e “53”.

String sete = String.valueOf(7); // chama valueOf(int) "7" String umPontoZero = String.valueOf(1.0f); // chama valueOf(float) "1.0"

System.out.printf("Nome: "); String user = "James Gosling"; int total = 53; System.out.printf("%s possui %d anos.\n", user, total);

Page 189: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Coleções, Arrays, String e Wrapper Classes

6-11

Wrapper Classes

Para cada tipo primitivo, Java fornece uma classe invólucro (wrapper class) correspondente. Estas classes permitem que um tipo primitivo seja manipulado como se fosse um objeto.

Cada classe invólucro fornece um método estático para converter uma string para o tipo primitivo correspondente.

Outros usos para Wrapper Classes

• Wrapper Classes são úteis quando você precisa tratar um tipo primitivo como um objeto. Java, por exemplo, define uma classe Vector, que implementa um vetor dinâmico de objetos (o tamanho do vetor pode ser alterado dinamicamente). Você não pode armazenar tipos primitivos em Vector. Neste caso, você precisará usar uma classe invólucro. Para armazenar, por exemplo, variáveis do tipo int em um Vector, você precisará criar um Integer para cada int: a classe Integer possui um construtor que faz isto.

• Wrapper Classes fornecem um local adequado para métodos de conversão relacionados ao tipo. A classe Integer, por exemplo, possui vários métodos, incluindo aí Integer.parseInt() para converter um tipo int em outro tipo.

• Wrapper Classes fornecem um local adequado para variáveis relacionadas ao tipo. Em Integer, por exemplo, Integer.MAX_VALUE representa o maior valor que um inteiro pode alcançar.

Tabela 6-1: Tipos primitivos e Wrapper Classes de apoio.

Tipo Primitivo

Classe invólucro correspondente

boolean Boolean

char Character

byte Byte

short Short

int Integer

long Long

double Double

float Float

Page 190: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Coleções, Arrays, String e Wrapper Classes

6-12

Conversões com Wrapper Classes

O exemplo abaixo mostra como usar os métodos de conversão para processar os campos de um formulário. Todos os campos textos guardam valores do tipo String. Temos, então, que ler os valores dos campos em variáveis do tipo String. No exemplo, é esperado um valor inteiro no primeiro campo e um valor real no segundo.

Métodos de conversão são necessários para converter um valor String para int e float respectivamente.

Observe que os métodos de conversão são chamados sem a necessidade de se instanciar um objeto Integer ou Float. As classes invólucros são um local adequado para métodos de conversão e não precisam ser instanciadas quando tais métodos são usados.

Código 6-19: Convertendo String para o tipo primitivo correspondente de acordo com a Wrraper Class.

O que acontece se o usuário entra com um valor não inteiro no primeiro campo?

Caso isto aconteça, parseInt() irá falhar e levantar uma exceção. Para tratar esta situação, seria necessário colocar código adicional para capturar e tratar a exceção levantada, tanto por parseInt(), quanto por parseFloat(). Exceções serão estudadas mais adiante. O código acima poderia ser feito da

seguinte forma:

Código 6-20: Convertendo String para o tipo primitivo correspondente de acordo com a Wrraper Class.

String qtdVal = qtdCampo.getText(); String prcVal = prcCampo.getText(); int qtd = Integer.parseInt(qtdVal); float prc = Float.parseFloat(prcVal);

int qtd = Integer.parseInt(qtdCampo.getText()); float prc = Float.parseFloat(prcCampo.getText()); // Suprimimos a declaração de variáveis

Quantidad

Preço:

17

425.00

qtdCamp

prcCampo

Page 191: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Coleções, Arrays, String e Wrapper Classes

6-13

StringBuffer e StringBuilder

StringBuffer e StringBuilder representam strings que podem ser modificadas e estendidas em tempo de execução. A primeira deve ser utilizada quando mais de uma thread estiver utilizando o objeto já a segunda quando somente uma thread estiver o utilizando pois o acesso a a mesma é mais rápida. Estas estruturas permitem você adicionar dados a um objeto sem que o mesmo precise ser recriado como é o caso da String. Estas estruturas são estruturas mutáveis ao contrário da String que é imutável.

O seguinte exemplo cria três novos objetos String e copia todos os caracteres cada vez que um novo objeto String é criado. Isto gera um overhead grande e deixa muitos objetos na memória para que o garbage collector os recolha.

Código 6-21: Concatenando Strings com o operador +.

É mais eficiente usar um objeto StringBuffer e seu método append():

Código 6-22: Concatenando Strings utilizando um StringBuffer

StringBuffer também fornece um comportamento semelhante a StringBuilder porém esta é uma estrutura que possui os seus métodos sincronizados, o que deixa o acesso aos mesmos mais lento quando temos somente uma thread acessando o objeto.

Você deve procurar utilizar StringBuilder em vez de StringBuffer. Veja abaixo um exemplo de StringBuilder e observe que a forma de uso dos mesmos é igual.

StringBuilder sb = new StringBuilder(); sb.append("Java J2EE\n"); sb.append("Oracle\n"); sb.append("PostgreSQL\n"); System.out.println(sb);

Código 6-23: Utilizando StringBuilder

String texto = "O texto começa com uma linha\n"; texto = texto + "E ganha outra linha\n"; texto = texto + "E mais uma...\n";

StringBuffer texto = new StringBuffer( "O texto começa com uma linha\n" ); texto.append( "E ganha outra linha\n" ); texto.append( "E mais uma...\n" );

Page 192: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Coleções, Arrays, String e Wrapper Classes

6-14

Arrays

Um vetor é uma coleção de variáveis do mesmo tipo. Cada elemento pode armazenar um único item. Os itens de um vetor podem ser de tipos primitivos ou referências para objetos.

O comprimento de um vetor é fixo, quando criado.

Vetores são úteis quando você deseja um grupo de objetos que possam ser manipulados como um todo. Caso você, por exemplo, escreva um programa para permitir a pesquisa por um filme, você provavelmente armazenará a lista de categorias em um vetor.

Figura 6-2: Estrutura de um vetor de Strings.

Page 193: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Coleções, Arrays, String e Wrapper Classes

6-15

Arrays de tipos primitivos

1. Declaração: Declare uma variável de referência para o vetor

2. Criação: Crie um vetor de objetos do tipo e tamanho desejados, e armazene a referência para este vetor na variável de referência (do passo 1)

3. Inicialização: Atribua os valores desejados para os elementos do vetor. Isto é opcional para um vetor de tipos primitivos porque os elementos recebem valores default quando o objeto vetor é criado.

De maneira esquemática, temos:

1. Declare a variável de referência que irá receber a referência para o objeto vetor

Figura 6-3: Referência inicial do vetor.

2. Cria o vetor (alocação de memória e inicialização default dos elementos do vetor)

Figura 6-4: Referência com vetor padrão int.

3. Atribuição de valores iniciais aos elementos do vetor

Figura 6-5: Referência com vetor padrão int inicializado.

Page 194: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Coleções, Arrays, String e Wrapper Classes

6-16

Declarando arrays de tipos primitivos

Há duas maneiras de se declarar um vetor: (tanto faz!!!)

Tabela 6-2: Declaração de vetores.

A maioria dos programadores Java usa o primeiro estilo porque ele separa o tipo da variável (no exemplo acima int) do nome da variável, tornando o código mais legível.

Quando você declara uma variável de referência para vetor, ela inicialmente recebe o valor null, até que o vetor seja efetivamente criado usando new.

Figura 6-6: Declaração do vetor nums.

Sintaxe Exemplo

tipo[] nome; int[] nums;

tipo nome[] int nums[];

Page 195: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Coleções, Arrays, String e Wrapper Classes

6-17

Criando arrays

Vetores devem ser criados usando o operador new. O tamanho do vetor deve ser especificado entre colchetes.O tamanho deve ser um inteiro, mas não precisa ser necessariamente uma constante. Pode ser uma expressão avaliável somente em tempo de execução. Uma vez que um vetor é criado, o seu tamanho permanece o mesmo por toda a existência do vetor.

Figura 6-7: Referência com vetor padrão int.

Todos os elementos de um novo vetor de tipos primitivos recebem automaticamente o valor default para o tipo:

• Elementos char recebem '\u0000';

• Elementos byte, short, int e long recebem 0;

• Elementos float e double recebem 0.0;

• Elementos boolean recebem false.

Código 6-24: Contruções válidas de vetores.

Código 6-25: Contruções inválidas de vetores.

// CONSTRUÇÕES VÁLIDAS // exemplo 1: tamanho é uma constante final int TAM = 4; int[] nums = new int[TAM]; // exemplo 2: tamanho conhecido apenas em tempo de execução int[] notasExame; int n = getTotalAlunos(); notasExame = new int[n];

// CONSTRUÇÕES INVÁLIDAS // exemplo 1: o tamanho não faz parte da declaração do vetor int nums[4]; // exemplo 2: n não foi devidamente inicializada int n; int[] nums = new int[n];

Page 196: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Coleções, Arrays, String e Wrapper Classes

6-18

Inicializando arrays

Primeiro Método: Atribua um valor para cada elemento

Para se referir a um elemento do vetor use um índice entre colchetes como mostrado no exemplo abaixo.

Os elementos de um vetor são indexados de 0 a n-1, onde n é o número de elementos do vetor. Em outras palavras, o índice do primeiro elemento de um vetor é sempre 0 e não 1.

Figura 6-8: Atribuição de valor int para o vetor

Segundo Método: Inicializadores de vetor

Como mostrado no exemplo abaixo, há uma construção simplificada para a criação e inicialização de vetores de tipos primitivos. Aqui não há necessidade de usar o operador new e o comprimento do vetor é automaticamente detectado.

Observe o uso de chaves e lembre-se de colocar o ponto e vírgula no final.

Figura 6-9: Declaração, criação e inicialização de vetor a partir de lista de valores int.

Inicializadores de vetor são muito úteis para criar tabelas de pesquisa, como mostrado no seguinte exemplo:

Código 6-26: Declaração, criação e inicialização de vetor a partir de lista de valores String.

int [] diasMes = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

Page 197: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Coleções, Arrays, String e Wrapper Classes

6-19

Este método é útil quando o valor de cada elemento é conhecido quando o vetor é criado.

Page 198: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Coleções, Arrays, String e Wrapper Classes

6-20

Arrays de objetos

Os passos para criar um vetor de referências são os mesmos que para criar um vetor de tipos primitivos, com uma única exceção: você deve sempre inicializar os elementos do vetor porque isto não é feito automaticamente.

1. Declaração: A sintaxe é a mesma para vetores de tipos primitivos. Por

exemplo:

Código 6-27: Declaração de vetor String.

2. Criação: A sintaxe é a mesma para vetores de tipos primitivos. Por

exemplo:

Código 6-28: Criação do vetor String com tamanho 3

A linha acima cria um objeto vetor do tipo String e de tamanho 3. Todos os elementos, no início, recebem o valor null.

3. Inicialização: Inicialize os elementos do vetor para o valor que desejar. Isto será visto com mais detalhes logo adiante.

String [] nomes;

nomes = new String [3];

Page 199: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Coleções, Arrays, String e Wrapper Classes

6-21

Declarando arrays de objetos

De maneira esquemática, temos:

1. Declare a variável de referência que irá receber a referência para o objeto vetor

Figura 6-9: Referência de vetor null.

2. Cria o vetor (alocação de memória e inicialização default dos elementos do vetor)

Figura 6-10: Criação do vetor de instâncias com tamanho 4 e valores null.

3. Atribuição de valores iniciais aos elementos do vetor

Figura 6-11: Inicialização do vetor com Strings.

Page 200: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Coleções, Arrays, String e Wrapper Classes

6-22

Inicializando arrays de objetos

Assim como para vetores de tipos primitivos, há duas maneiras de se inicializar um vetor de referências para objetos.

Você pode inicializá-lo, atribuindo um valor para cada elemento do vetor, ou declarando um inicializador ao criá-lo.

Código 6-29: Código para inicialização de vetor.

Código 6-30: Criando vetor de String a partir de uma lista de Strings.

A Propriedade length

Cada vetor tem um atributo length que contém o número de elementos do vetor. Ao usar length, você evita ter de armazenar o tamanho do vetor em outra parte de seu código.

A classe System fornece um método útil para copiar todo ou parte de um vetor para outro vetor. Para maiores informações, consulte System.arrayCopy() na documentação do J2SDK.

// Inicializa elemento por elemento // Cria um vetor de 4 Strings vazias String[] array = new String[4]; for(int i=0; i<array.length; i++) { arr[i] = new String(); }

// Inicializadores String[] produtos = {"CD", "DVD", "VHS", "MP3"}

Page 201: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Coleções, Arrays, String e Wrapper Classes

6-23

Utilizando arrays de objetos

Um vetor se comporta como objetos. Sendo assim, quando um vetor é passado para um método, na verdade, uma referência para este vetor é passada. Portanto, se o método altera o conteúdo do vetor, estas mudanças alterarão o vetor original (e não uma cópia).

Qualquer elemento de um vetor pode receber um objeto do tipo correto, e também ser atribuído a uma variável de tipo compatível. Cada elemento de um vetor pode ser tratado como um objeto individual.

Um elemento de vetor pode ser passado para um método, e neste caso, por ser um objeto, a referência para o objeto é que será passada.

Código 6-31: Vetor de referência para objetos String.

String[] produtos = new String[4]; // ... String produto = produtos[0]; produtos[1] = "Caneta";

System.out.println("Length: " + produtos[0].length());

Page 202: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Coleções, Arrays, String e Wrapper Classes

6-24

Arrays e Exceções

Exceções são levantadas dependendo de como vetores são manipulados. Caso você tente acessar uma posição inválida de um vetor, o programa será interrompido pela exceção ArrayIndexOutOfBoundsException.

Caso tente acessar um elemento de um vetor que não tenha sido inicializado, a exceção NullPointerException será levantada.

Código 6-32: Exceções comuns a partir de vetores.

// Exceção ArrayIndexOutOfBoundsException String[] lista = new String[4]; System.out.println(lista[5]); // Exceção NullPointerException Produto[] listaProdutos = new Produto[3]; String nomeProduto = listaProdutos[0].getNome();

Page 203: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Coleções, Arrays, String e Wrapper Classes

6-25

Arrays multidimensionais

Java suporta vetores multidimensionais, isto é, vetor de vetores.

Código 6-33: Declarando e criando uma matriz.

A linha acima declara e cria uma matriz bidimensional: a matriz contém cinco linhas e cada uma das linhas possui quatro colunas. Elementos individuais podem ser acessados da seguinte maneira:

Código 6-34: Esquema de acesso a uma matriz.

O seguinte exemplo cria um vetor multidimensional com dez linhas, mas o número de colunas por linha é diferente. A primeira linha possui apenas um elemento, a segunda dois, a terceira três e assim por diante.

Código 6-35: Criação de matriz com número de colunas diferentes.

Exemplo de um vetor multidimensional:

Figura 6-12: Visão geral de estrutura e implementação de matrizes.

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

matriz[indiceLinha][indiceColuna] = valor;

int[][] a = new int[10][]; for(int i=0; i<a.length; i++) { a[i] = new int[i+1]; }

Page 204: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Coleções, Arrays, String e Wrapper Classes

6-26

O método main(String[] args)

Uma referência para um vetor pode ser passada para qualquer método. Um bom exemplo sito é o método main() usado nas aplicações Java. Quando você inicia uma aplicação Java, o sistema localiza e chama o método main() para esta classe.

O método main() recebe um único parâmetro, que é uma referência para um vetor de objetos String. Cada objeto String guarda um parâmetro da linha de comando.

O primeiro elemento do vetor contém o primeiro parâmetro da linha de comando, e não o nome do programa, como ocorre em C ou C++.

É importante notar que os parâmetros da linha de comando são sempre representados por objetos String. Dentro do método main(), você pode converter os parâmetros para tipos primitivos.

Se um dos parâmetros, por exemplo, representar um número, você deverá convertê-lo para um int para que possa realizar operações aritméticas com ele. Métodos de conversões foram vistos anteriormente.

Na versão do J2SDK 1.5 temos a seguinte possibilidade de receber o vetor de

Strings:

Código 6-36: Recepção de parâmetros utilizando J2SDK 1.5.

Utilizamos a expressão “...” para representar uma String dinâmica.

public class Test { public static void main(String... args) { System.out.println(args.length + " argumentos"); } }

Page 205: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Coleções, Arrays, String e Wrapper Classes

6-27

API Colletion

Em Java a API Collection é referenciada como um framework. Este framework fornece um conjunto bem defindo de interfaces e classes para armazenar e manipular grupos de dados, conhecidos como coleções. Este framework fornece uma conveniente API para muitos dos tipos de dados abstratos das estruturas: Map, Set, List, Tree, Array, Hashtable e outras coleções.

Este frameword está dentro do pacote java.util, desta forma este pacote deve ser sempre importado quando se desejar trabalhar com coleções.

Uma simples collection não coloca nenhuma restrição sobre os tipos de elemento, ordem dos elementos, ou repetição dos elementos dentro da collection.

Em java,a interface java.util.Collection define a collection básica de framework para todos tipos de collections. A Interface Collection possui métodos que permitem você adicionar itens, remover itens, pesquisar, e contar o número de elementos na collection.

Principais métodos:

- boolean add(Object element) - boolean remove(Object element) - void clear() - int size() - boolean isEmpty() - Object[] toArray()

Page 206: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Coleções, Arrays, String e Wrapper Classes

6-28

A interface Iterator

Um Iterator é um objeto que pode ser utilizado para percorrer coleções. Com os métodos da interface Iterator, você pode percorrer uma collection do início ao fim e de forma segura remover os elementos da Collection. O iterator geralmente usa operações de busca.

Métodos:

- remove() - hasNext() - next()

Veja abaixo o código exemplo para percorrer uma coleção do tipo ArrayList utilizando a interface iterator

ArrayList lista = new ArrayList(); ... Iterator it = lista.iterator(); while ( it.hasNext() ) { String s = (String)it.next(); ... }

Código 6-37: Iterator

Page 207: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Coleções, Arrays, String e Wrapper Classes

6-29

A interface Enumeration

A interface Enumeration permite você percorrer todos os elementos de uma collection. Percorrer uma collection com uma Enumeration é semelhante a percorrer com um Iterator. Emumeration não oferece suporte para remover elementos, coisa esta que você pode fazer com um Iterator.

Métodos:

- boolean hasMoreElements(); - Object nextElement();

Veja abaixo um exemplo de código para percorrer uma Enumeration:

Hashtable tabela = new Hashtable(); ... Enumeration elementos = tabela.elements(); while ( elementos.hasMoreElements() ) { Produto p = (Produto)elementos.nextElement(); ... }

Código 6-38 Enumeration

Page 208: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Coleções, Arrays, String e Wrapper Classes

6-30

Interfaces do framework

Neste framework existem várias interfaces que podem ser utilizadas, estas interfaces são estruturas que permitem armazenar objetos de formas específicas. Vamos ver algumas delas abaixo.

Interface Set

No conceito matemático, um conjunto é justamente um grupo de itens únicos, sem elementos duplicados.

A interface Set estende a interface Collection. Set não permite duplicatas dentro da collection. Na implementação Set, null é uma entrada válida, mas permitida somente um por vez.

Interface List

Como o próprio nome já nos diz, representa uma lista que permite duplicatas. A interface List estende a interface Collection. Existem duas List implementations disponíveis na Collections Framework: ArrayList e LinkedList.

A Interface Map

Um map é um tipo especial de grupo sem duplicatas. Dentro da Collections API, java.util.Map define esta interface. Ele mapeia os valores chaves para os objetos armazenadao. O valores chaves são usados para procurar, ou indexar os dados armazenados.

A interface Map não é uma extensão da interface Collection , ele possui sua própria hierarquia. Map não permite duplicatas dentro da collection. Na implemantação Map , null é uma entrada válida, mas só é permitido uma vez. Vamos estudar aqui uma implementação desta interface: Hashtable

Page 209: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Coleções, Arrays, String e Wrapper Classes

6-31

A classe ArrayList

Implementa a interface java.util.List e usa array para armazenamento. Um armazenamento de array é geralmente mais rápido, mas possui limitações como, não poder inserir, e apagar entradas no meio da lista. Para realizar este tipo de adição e exclusão precisamos de um novo array, e isto gera portanto um overhead muito grande. Você pode acessar qualquer elemento aleatoricamente.

Esta estrutura não é sincronizada, devendo ser utilizada quando o acesso a um objeto desta classe tiver uma única thread.

Código 6-39: Exemplo de ArrayList

package com.targettrust.exemplos; import java.util.*; /** * - Elementos não ordenados * - Permite duplicados * - null É permitido * - Semelhante a classe Vector * - Acesso aleatório */ public class ArrayListExemplo { public static void main(String[] args) { List lista = new ArrayList(); lista.add("Java J2EE"); lista.add("Microsoft Net"); lista.add("Linux"); lista.add("Oracle"); lista.add("Web Designer"); lista.add("Java J2EE"); lista.add(null); System.out.println( lista.get(0)+", "+lista.get(4) ); // [Java J2EE, Web Designer] } }

Page 210: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Coleções, Arrays, String e Wrapper Classes

6-32

A classe Vector

Uma vez que o tamanho do array é definido você não pode mudar o tamanho do array. Mas em java isso é possivel utilizando o mecanismo de refleção do Java que foi introduzido no Java 1.1, mas ele possui suas próprias limitações.

Esta classe possui os seus métodos sincronizados desta forma deve ser utilizada quando o acesso ao objeto for concorrente. Já se o acesso não tiver esta característica então deve ser utilizada a classe ArrayList que não é sicronizada e é, portanto, mais rápida.

Para lidar com este tipo de situação em Java utilize Vector, ele cresce e reduz seu próprio tamanho automáticamente. Isso permite somente objetos que não são primitivos. Para enviar primitivas, converta as primitivas à um objeto e envie elas para o vector.

O vector realoca e redefine o tamanho automáticamente . Veja o exempo seguinte.

Vector vt = new Vector(3, 10);

As linha acima representam a capacidade inicial de três, e cresce em aumento de 10 em cada realocação quando se tenta adicionar o quarto elemento. Depois de realocado a capacidade do vector se torna a capacidade inicial + a capacidade aumentada (capacity Increment).

Construtores:

- Vector(int initialCapacity); - Vector(int initialCapacity, int capacitIncrement); - Vector()

Métodos:

- void addElement(Object obj); - int size(); - void setSize(int n); - void trimToSize();

Page 211: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Coleções, Arrays, String e Wrapper Classes

6-33

Vejamos agora abaixo um exemplo com a classe Vector:

Código 6-40: Exemplo de Vector.

package com.targettrust.exemplos; import java.util.*; /** * - Elementos não ordenados * - Permite duplicados * - null É permitido * - Acesso aleatório */ public class VectorExemplo { public static void main(String[] args) { Vector lista = new Vector(); lista.add("Java J2EE"); lista.add("Microsoft Net"); lista.add("Linux"); lista.add("Oracle"); lista.add("Web Designer"); lista.add("Java J2EE"); lista.add(null); System.out.println( lista.get(0) ); System.out.println( lista ); // [Java J2EE] // [Java J2EE, Microsoft Net, Linux, Oracle, Web Designer, Java J2EE, null] } }

Page 212: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Coleções, Arrays, String e Wrapper Classes

6-34

A classe Hashtable

Hashtable é uma estrutura que possui os elementos armazenados internamente baseados em chave. Todo objeto guardado dentro desta estrutura ficará associado a uma chave para posterior recuperação do mesmo. Esta estrutura é uma das mais rápidas quando o assunto é pesquisa, uma vez que o acesso ao objeto armazenado é direto através de chaves. Veja um exemplo abaixo: package com.targettrust.exemplos; import java.util.*; /** * - Elementos não ordenados * - NÃO permite duplicados * - null NÃO é permitido * - Acesso baseado em chave */ public class HashtableExemplo { public static void main(String[] args) { Hashtable lista = new Hashtable(); lista.put(new Integer(1), "Java J2EE"); lista.put(new Integer(2), "Microsoft Net"); lista.put(new Integer(3), "Linux"); lista.put(new Integer(4), "Oracle"); lista.put(new Integer(5), "Web Designer"); lista.put(new Integer(6), "Java J2EE"); System.out.println( lista.get(new Integer(1)) ); System.out.println( lista.get(new Integer(4)) ); // [Java J2EE] // [Oracle] } }

Código 6-41: Hashtable

Page 213: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Coleções, Arrays, String e Wrapper Classes

6-35

A classe LinkedList

Implementa a interface java.util.List e usa linked list para armazenamento. Uma linked list permite que elementos sejam adicionados, removidos da collection em qualquer posição dentro do container. Com esta implementação você somente pode acessar os elementos sequencialmente.

Veja abaixo um exemplo de uso desta estrutura:

Código 6-42: Exemplo de LinkedList.

package com.targettrust.exemplos; import java.util.*; /** * - Elementos não ordenados * - Permite duplicados * - null É permitido */ public class LinkedListExemplo { public static void main(String[] args) { List lista = new LinkedList(); lista.add("Java J2EE"); lista.add("Microsoft Net"); lista.add("Linux"); lista.add("Oracle"); lista.add("Web Designer"); lista.add("Java J2EE"); lista.add(null); System.out.println( lista ); // [Java J2EE, Microsoft Net, Linux, Oracle, Web Designer, Java J2EE, // null] } }

Page 214: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Coleções, Arrays, String e Wrapper Classes

6-36

Generics

Os tipos genéricos representam uma das maiores modificações na

linguagem java já feitas até os dias de hoje. Tipos genéricos trazem a facilidade de parametrizar o tipo de classes, variáveis ou métodos. Na API do JDK 5.0 todas as collection, por exemplo, foram parametrizadas. Esta parametrização tornou classes como, por exemplo, ArrayList capazes de armazenar elementos de um tipo “E” e não mais Object. A declaração de ArrayList, por exemplo, agora pode ser feita da seguinte forma:

1 ArrayList<Aluno> alunos = new ArrayList<Aluno>(); 2 3 Aluno a = new Aluno("Rafael"); 4 alunos.add( a ); 5 6 Aluno x = alunos.get( 0 ); 7 System.out.println("Nome: "+ x.getNome() );

Código 6-43: Generics

Observe o código acima e perceba que na linha 6 não foi preciso realizar

um “casting” para converter o objeto retirado da coleção. O mesmo havia sido armazenado internamente como um objeto Aluno e não como sendo do tipo “Object”.

Além de simplificar a codificação, os tipos genéricos também são uma

grande melhoria de robustez, evitando a possibilidade de typecasts errados e, portanto a ocorrência de ClassCastException. Isto também, é claro, aumenta a produtividade, pois perde-se menos tempo com depuração e testes – se o código compila, é porque vai funcionar, pelo menos no que diz respeito a tipos.

Com os tipos genéricos, o programador pode formalizar restrições

adicionais dos tipos que constrói, por exemplo, determinar que determinada lista só possa conter instâncias de Produto, e não objetos quaisquer. Violações dessas regras de tipagem não são críticas para a linguagem (pois não possibilitam perda de dados nem corrupção de memória), mas são críticas para o desenvolvedor, pois poderão ocultar erros de lógica. O resultado pode ser uma ClassCastException, ou – ainda pior – o bug pode ficar oculto por muito tempo, pois o valor opaco (Object) é convertido para o tipo que deveria ter. import static java.lang.System.*; ... ... Aluno a = new Aluno("João", "(51) 3325-2596" ); Map<String, Aluno> hash = new HashMap<String, Aluno>(); // Adiciona um aluno na Hash hash.put(a.getNome(), a); // Recupera o Aluno Aluno x = hash.get( a.getNome() );

Page 215: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Coleções, Arrays, String e Wrapper Classes

6-37

// Mostra dados out.printf( "Dados: %s %s", x.getNome(), x.getTelefone() );

Código 6-44: Usando generics

Acima você tem um código onde criamos uma HashMap para adicionar

objetos do tipo Aluno associados a chaves do tipo String. Na declaração de HashMap especificamos que a chave será do tipo String bem como os objetos a serem armazenados serão Alunos, isto evita qualquer necessidade de “casting” posterior para recuperar os dados da estrutura, bem como fortalece o sistema de tipos proibindo que sejam utilizados tipos diferentes dos especificados na declaração. A linha abaixo não compilaria pois o tipo da chave esta sendo violada. hash.put(new Integer(1), a); //ERRO ao compilar!

Código 6-45: Adicionando inteiro como chave

Podemos também cria uma classe com tipos parametrizados. A classe

abaixo representa um grupo no qual podemos guardar objetos. Os objetos a serem armazenados neste grupo são sempre do tipo especificado no parâmetro “T” da classe Grupo. Veja o código da classe: public class Grupo<T> { private ArrayList elementos; public Grupo() { elementos = new ArrayList(); } public void add(T obj) { elementos.add( obj ); } public void remove(T obj ) { elementos.remove( obj ); } }

Código 6-46: Criando uma classe de um determinado tipo

Podemos criar um objeto da classe grupo da seguinte forma: Grupo<String> g = new Grupo<String>(); g.add( "Java J2ME" ); g.add( "Java J2EE" ); g.add( new Integer(3) ); // ERRO!

Código 6-47: Criando grupo de Strings

Observe que na linha onde tentamos adicionar um inteiro teremos

problemas, pois o grupo foi criado como sendo capaz de armazenar somente Strings. O tipo do grupo pode ser trocado conforme o código abaixo:

Grupo<Aluno> g = new Grupo<Aluno>();

Page 216: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Coleções, Arrays, String e Wrapper Classes

6-38

Aluno a = new Aluno("João", "(51) 3325-2596" ); g.add( a ); g.add( "Java J2EE" ); // ERRO! g.add( new Integer(3) ); // ERRO!

Código 6-48: Violando acesso ao grupo

O código acima foi alterado para receber objetos aluno e armazenar dentro do grupo. Veja que a linha onde adicionamos agora uma String ou um Integer irá sinalizar erro. Neste exemplo acima os parâmetros do método add(...) bem como do remove(...) estão parametrizados. Teríamos outra opção para não utilizar os parâmetros genéricos, bastaria definir o tipo dos métodos como Object. Desta forma poderia ser criado um grupo e passado qualquer tipo de objeto para ele, mas isto permitiria que o grupo pudesse armazenar tipos diferentes de objetos. Para evitar isto você também poderia tornar os tipos dos parâmetros doa métodos fixos (String, por exemplo), mas desta forma você teria somente um grupo de strings e não poderia criar grupos de outros objetos. Observe que neste caso o objetivo é justamente permitir que se possa criar um grupo de tipos variáveis, mas uma vez definido um grupo como sendo de um tipo, o mesmo não poderá receber elementos de outros tipos.

Page 217: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Coleções, Arrays, String e Wrapper Classes

6-39

Autoboxing

Autoboxing diz respeito a uma conversão automática que é feita entre os tipos primitivos da linguagem java (int, float, long, byte, etc...) e suas wrapper classes (Integer, Float, Long, Byte, Character, etc...). O programador não precisa mais se preocupar com estas conversões ficando a cargo agora da linguagem. Este recurso é interessante e simplifica a escrita de códigos porém introduz alguns efeitos colaterais listados mais abaixo. Deve desta forma ser utilizado de forma controlada.

Integer i = 10; System.out.println( i );

Código 6-49: Autoboxing

O código acima atribui um valor primitive (10) a um objeto do tipo Integer.

Logo em seguida o objeto integer é impresso. Um exemplo: Quando trabalhamos com Collections sabemos que à uma coleção pode ser adicionado somente objetos, não sendo possível portanto adicionar um tipo primitivo a esta. Para isto o tipo primitivo deve ser encapsulado em uma wrapper class e então o objeto desta wrapper adicionado a Collection. Veja código abaixo: ArrayList lista = new ArrayList(); // Criando os objetos Integer um = new Integer(1); Integer dois = new Integer(2); Integer tres = new Integer(3); // Adicionando os objetos a Collection lista.add ( um ); lista.add ( dois ); lista.add ( tres );

Código 6-50: Adicionando dados em uma coleção

A mesma dificuldade de manipulação ocorre quando temos que retirara o valor da coleção, pois se precisarmos manipular o valor como um tipo primitivo isto exigirá, além de um casting, uma chamada a um método do objeto retirado para o transformar novamente em um tipo primitivo. Todo este processo de encapsular e desencapsular é conhecido como: boxing e unboxing. Isto deixa o código maior e mais complicado de ser escrito.

Page 218: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Coleções, Arrays, String e Wrapper Classes

6-40

Veja abaixo a versão do mesmo agora para retirar os elementos: // Retira os objetos da coleção Integer x = (Integer)lista.get(0); Integer y = (Integer)lista.get(1); Integer z = (Integer)lista.get(2); // Mostrar os valores em formato int System.out.println( x.intValue() ); System.out.println( y.intValue() ); System.out.println( z.intValue() );

Código 6-51: Mostrando dados da coleção sem autoboxing

Podemos utilizar autoboxing para resolver e simplificar a escrita deste código. Veja abaixo a versão do código que adiciona os três valores dentro da collection. Observe que utilizamos para isto um tipo de collection que comporta somente Integer. Esta forma de representação de collection faz uso de Generics. ArrayList<Integer> lista = new ArrayList<Integer>(); // Adicionando dados a Collection lista.add ( 1 ); lista.add ( 2 ); lista.add ( 3 ); // Retira os dados da collection int x = lista.get(0); int y = lista.get(1); int z = lista.get(2); // Mostra os dados da collection System.out.println( x ); System.out.println( y ); System.out.println( z );

Código 6-52: Utilizando autoboxing para mostrar dados

Comparando valores encapsulados: Ao compararmos valores que foram encapsulados através do recurso de autoboxing, temos que tomar muito cuidado. Veja o código abaixo e os tipos de retorno. int i = 2; int j = 2; ArrayList <Integer> lista = new ArrayList<Integer>(); lista.add(i); lista.add(j); System.out.println( (i==j) ); System.out.println( lista.get(0)==lista.get(1) );

Page 219: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Coleções, Arrays, String e Wrapper Classes

6-41

System.out.println( lista.get(0).equals( lista.get(1) ) );

Código 6-53: Comparando dado s de uma coleção

As saídas para o código acima são as seguintes: true true true

A primeira comparação esta comparando tipos primitivos e como já sabemos a saída deveria ser true. Já no segundo caso são comparados os valores que foram enpasulados (“autoboxed”), retornando também true. No terceiro caso são comparados os valores dos objetos criados através de autoboxing.

Se o valor das variáveis inteiras forem alteradas para um valor superior a

127, o retorno para a comparação lista.get(0)==lista.get(1) será false! Note que estamos neste caso comparando os valores enpasulados como objetos e não os valores primitivos diretamente. Para as demais comparações o retorno continua sendo true. Abaixo a saída para os valores alterados e superiores a 127:

true false true

Page 220: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Coleções, Arrays, String e Wrapper Classes

6-42

Espaço para anotações

Page 221: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Coleções, Arrays, String e Wrapper Classes

6-43

Exercícios

1. Neste exercício você irá criar uma classe nova para representar um

pacote de cursos. Um pacote de cursos contém vários cursos. Teremos que saber quantos há neste pacote, bem como o valor total do pacote. Este valor será a soma do preço de todos os cursos. Veja abaixo os passos para isto:

Passo 1: Crie uma classe pública chamada PacoteCurso no pacote

com.targettrust.java e defina os seguintes atributos:

private ArrayList<Curso> cursos private Date dataCriacao

Page 222: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Coleções, Arrays, String e Wrapper Classes

6-44

Observe no atributo acima o uso de generics para definir o tipo de objetos da coleção

Passo 2: Crie no método construtor o ArrayList.

Passo 3: Defina nesta classe uma operação que possa receber objetos da classe curso e os adiciona a coleção cursos. Quando esta coleção atingir um número de 10 cursos deve ser impresso um aviso.

Passo 4: Crie nesta classe uma operação capaz de calcular o valor total do pacote. Para fazer este cálculo você deverá percorrer a coleção e obter o preço de cada curso adicionado a ela. Use for-each para percorrer o ArrayList.

Passo 5: Crie uma operação na classe PacoteCurso para que a mesma retorne uma StringBuilder contendo o nome de todos os curos que fazem parte do pacote.

2. Agora você irá praticar o mecanismo de autoboxing do java. Vamos criar um ArrayList com números inteiros e percorrer o mesmo somando estes valores.

Passo 1: Crie uma classe chamada ExemploAutoboxing no pacote com.targettrust.java e declare nesta classe o método main.

Passo 2: Na classe declare um atributo privado, chamado lista, estático, do tipo ArrayList. Utilize Generics na declaração do atributo ( ArrayList<Integer> ) No método main crie este objeto que representa a lista e adicione no mesmo 5 números do tipo int.

Passo 3: Percorra a lista com um for-each e some todos os números da lista mostrando o total ao término do laço. Observe que não haverá casting para a soma dos números!

Page 223: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Java Fundamentals

7-1

77.. TTrraattaammeennttoo ddee EExxcceeççõõeess

Page 224: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tratamento de Exceções

7-2

Objetivos

• Compreender as Vantagens do tratamento de Exceções em Java;

• Manipular, Tratar, Propagar, Capturar e Criar Exceções.

Page 225: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tratamento de Exceções

7-3

Introdução

Uma exceção é um evento que ocorre durante a execução de um programa que interrompe o fluxo normal das instruções. Muitos tipos de erros podem causar exceções, tais como tentar acessar um elemento de um vetor fora dos limites ou tentar dividir um número por zero.

Quando uma exceção ocorre dentro de um método Java, o método cria um objeto Exception e deixa que o ambiente de execução (runtime system) se encarregue do assunto. Na terminologia Java, este processo é chamado levantar uma exceção (throwing an exception).

O objeto Exception criado contém informações sobre a exceção, tais como seu tipo e o estado do programa quando o erro ocorreu.

Após o método levantar uma exceção, o ambiente de execução é então responsável por encontrar um código que manipule o erro. Para isso, o ambiente de execução entra em ação procurando o código de tratamento para o erro no conjunto de métodos da pilha de chamada do método em que o erro ocorreu.

O ambiente de execução procura de trás para frente na pilha de chamada, começando com o método onde o erro ocorreu, até encontrar um método que contenha a manipulação apropriada da exceção.

Uma manipulação de exceção é considerada apropriada se o tipo de exceção levantada é o mesmo tipo de exceção manipulada pelo manipulador (pelo código de tratamento da exceção).

Assim, a exceção cruza a pilha de chamadas até que uma manipulação apropriada é encontrada e um dos métodos chamados trata a exceção. Na terminologia Java, se diz que o manipulador escolhido para tratar a exceção capturou (catch the exception) a exceção.

Se o ambiente de execução procura exaustivamente em todos os métodos da pilha de chamadas sem descobrir um manipulador de exceções apropriado, o ambiente de execução (e conseqüentemente, o programa Java) termina.

A utilização de exceções para manipular erros tem as seguintes vantagens sobre as técnicas de gerenciamento de erros tradicionais:

1. Separa o código para manipular erros do código regular (do fluxo normal) do programa

2. Propaga erros na pilha de chamadas

3. Agrupa tipos de erros e os diferencia

4. Não podem ser ignoradas

Page 226: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tratamento de Exceções

7-4

1a Vantagem: Separação de Código

Na programação tradicional, a detecção e manipulação de erros tornam o código freqüentemente mais difícil de compreender. Como exemplo, suponha que se tenha uma função que leia a primeira linha de um arquivo.

Um esquema do código para esta função seria:

Código 7-1: Exemplo de código estruturado para tratamento de arquivos.

Esta função poderia ter diversos erros potenciais, tais como erro na abertura do arquivo, erro na leitura da primeira linha, erro no fechamento do arquivo.

No modo de programação tradicional para detectar os potenciais erros para esta função, cada erro deve ser testado e atribuído para um código de erro. Isto leva a uma grande quantidade de código adicional para a detecção e manipulação dos possíveis erros.

Por exemplo, a função anterior se tornaria uma função tal como:

Código 7-2: Exemplo de código condicional para tratamento de arquivos com retorno de valor.

Na linguagem Java, o problema de tratamento de erros é realizado a partir exceções.

As exceções permitem que o programador escreva o código do fluxo principal e manipule os casos excepcionais em outro local.

int leituraArquivo { abre o arquivo; le o arquivo; fecha o arquivo;

}

int leituraArquivo { int codigoErro = 0; abre o arquivo;

if (erroAberturaArquivo) codigoErro = -1; else { le o arquivo;

if (erroLeituraArquivo) codigoErro = -2; fecha o arquivo; if (erroFechamentoArquivo) codigoErro = -3; } return codigoErro; }

Page 227: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tratamento de Exceções

7-5

A função exemplo anterior se tornaria uma função tal como:

Código 7-3: Exemplo de código estruturado para tratamento de arquivos utilizando Java.

Como pode ser visto, as exceções não dispensam a detecção e manipulação dos erros.

O que elas fornecem são meios de separar da lógica principal todos os detalhes do que fazer quando algum evento fora do normal ocorre. Com isso, o código se torna mais claro e menos propenso a erros.

leituraArquivo { try { abre o arquivo;

le o arquivo;

fecha o arquivo;

} catch (erroAberturaArquivo) { manipula erro } catch (erroLeituraArquivo) { manipula erro } catch (erroFechamentoArquivo) { manipula erro } }

Page 228: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tratamento de Exceções

7-6

2a Vantagem: Propagação de Erros

A segunda vantagem do uso de exceções é a habilidade de propagar a informação do erro através dos métodos da pilha de chamadas.

Uma exceção em Java é enviada imediatamente para o manipulador apropriado, sem a necessidade do comando if em cada nível para transmitir o erro acima na pilha de chamadas.

Suponha que o método do exemplo anterior, leituraArquivo, é o quarto método em uma série de chamadas de métodos aninhados feitas pelo programa principal: metodo1 chama o metodo2, que chama o metodo3, que chama leituraArquivo.

O metodo1 é o único método interessado nos erros que ocorrem dentro do método leituraArquivo, e é o método que manipula estes erros. Na técnica de programação tradicional, o metodo2 e o metodo3 teriam que propagar os códigos de erros retornados por leituraArquivo adiante na pilha de chamadas até que os códigos de erros finalmente atingissem metodo1, o único método interessado nestes erros.

Assim, na programação tradicional, seria necessário:

1. leituraArquivo tenta executar sua função e retorna um código de erro para metodo3

2. metodo3 verifica a existência de erros e transmite o código de erro para metodo2

3. metodo2 verifica a existência de erros e transmite o código de erro para metodo1

4. metodo1 verifica a existência de erros e trata os erros ocorridos.

Na manipulação de exceções em Java, contudo, o ambiente de execução procura de trás para frente na pilha de chamadas, procurando descobrir algum método que está interessado em manipular uma exceção em particular.

Um método Java pode levantar qualquer exceção dentro dele, permitindo assim que um método adiante na pilha de chamadas possa capturar esta exceção. Com isso, apenas os métodos interessados devem se preocupar em detectar erros.

Deste modo, manipulando exceções, é necessário:

1. leituraArquivo levanta uma exceção

2. metodo1 captura a exceção

Page 229: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tratamento de Exceções

7-7

Além disso, as exceções que podem ser levantadas dentro de um método são parte da interface de programação pública do método e devem ser especificadas na cláusula throws do método.

Com isso, o método informa aos seus chamadores sobre as exceções que ele pode levantar e estes métodos podem decidir de modo inteligente o que fazer com tais exceções.

O trecho a seguir demonstra como ficariam os métodos metodo1, metodo2 e metodo3 manipulando exceções. Como pode ser visto, este código é mais compacto que na programação tradicional.

Código 7-4: Propagação de exceções utilizando a cláusula throws.

public void metodo1() { try { chamada de metodo2; } catch (exception) { trata erro; } } public void metodo2() throws exception { chamada de metodo3; } public void metodo3() throws exception { chamada de lePrimeiraLinhaArquivo; }

Page 230: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tratamento de Exceções

7-8

3a Vantagem: Agrupar Tipos de Erros

As exceções freqüentemente se enquadram em categorias ou grupos. Por exemplo, os erros que podem ocorrer na manipulação de um vetor (tais como índice fora do intervalo do tamanho do vetor e inserção de elemento de um tipo errado) podem ser facilmente imaginados como um grupo de exceções, cada exceção representando um dos tipos de erro.

Do mesmo modo, os erros que podem ocorrer em operações de E/S (tais como tentar abrir um arquivo com nome inválido e interrupção da operação de E/S) são facilmente imaginados como um grupo de exceções.

Além disso, é fácil imaginar que alguns métodos queiram fazer o tratamento das exceções que se enquadrem numa categoria (por exemplo, todas as exceções referentes a vetores), e outros métodos queiram manipular apenas exceções específicas (por exemplo, apenas a inserção de um elemento de tipo errado no vetor).

Todas as exceções que são levantadas dentro de um programa Java são objetos first-class. Deste modo, o agrupamento de exceções é um resultado natural da hierarquia de classes. As exceções em Java devem ser instâncias de Throwable, ou qualquer descendente de Throwable.

Assim como em outras classes, subclasses da classe Throwable podem ser criadas. Cada classe sem subclasses (folha) representa um tipo específico de exceção e cada classe com uma ou mais subclasses (nodo) representa um grupo de exceções.

No esquema abaixo, IOException é uma subclasse de Exception (uma subclasse de Throwable) e possui duas subclasses:

• FileNotFoundException

• InterruptedIOException.

A classe IOException é uma classe geral de exceções produzidas por falha ou interrupção de operações de E/S. As suas duas subclasses representam dois tipos de erro específicos que podem ocorrer em operações de E/S.

Page 231: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tratamento de Exceções

7-9

Figura 7-1: Hierarquia de classes para tratamento de arquivos.

Um exemplo de manipulador de exceção que trata somente exceções geradas ao tentar abrir um arquivo com nome inválido

(FileNotFoundException) é:

Código 7-5: Bloco catch para tratamento de exceção específica.

Um método pode também capturar uma exceção baseada em seu grupo ou tipo geral. Isto é feito especificando qualquer uma das superclasses de exceções no comando catch. Para capturar todas as exceções de E/S, independente do seu tipo, a manipulação de exceções poderia especificar o argumento IOException, como no exemplo abaixo.

Esta manipulação iria capturar todas as exceções deste grupo. Para descobrir exatamente que tipo de exceção ocorreu, o parâmetro e poderia ser

usado.

Código 7-6: Bloco catch para tratamento de exceção de grupo (IOException).

É possível também utilizar um manipulador de exceções que trate qualquer

exceção:

Código 7-7: Bloco catch para tratamento de qualquer exceção.

Manipuladores de exceções que são muito genéricos, como o mostrado acima, podem tornar o código mais propenso a erros por capturar e tratar exceções que não foram previstas e que, portanto, não serão corretamente tratadas dentro do manipulador.

Deste modo, manipuladores de exceções gerais não devem ser utilizados como uma regra.

catch (FileNotFoundException e) { tratamento da exceção }

catch (IOException e) { tratamento }

catch (Exception e) { tratamento }

Page 232: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tratamento de Exceções

7-10

4a Vantagem: Exceções não são Ignoradas

Após um método levantar uma exceção, ela não pode ser ignorada: ela precisa ser capturada e manipulada em algum local.

Page 233: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tratamento de Exceções

7-11

Manipulando Exceções

A classe Throwable é a superclasse de todos os erros e exceções na linguagem Java, possuindo duas subclasses: Error e Exception.

Figura 7-2: Hierarquia de erros Java.

Subclasse Error

Erros são extensões da classe Error, subclasse de Throwable. Subclasses de Error, diferente das subclasses de Exception, geralmente não devem ser capturadas, e geralmente causarão o término do programa.

Exemplos deste tipo de erro são falta de memória durante a execução ou não estar apto a carregar uma classe.

Exceções não verificadas (Unchecked Exceptions)

Exceções não verificadas (exceções de execução) são extensões da classe RuntimeException. Estas exceções são aquelas que ocorrem dentro do ambiente de execução Java (JVM). Possíveis exemplos são exceções aritméticas (tal como divisão por zero), exceções de ponteiro (tal como tentar acessar um objeto utilizando uma referência nula) e exceções de indexação (tal como tentar acessar um elemento de um vetor utilizando um índice muito grande).

As exceções de execução podem ocorrer em qualquer local do programa e o custo para testar se elas realmente ocorrerão é freqüentemente maior que o benefício de capturá-las. Assim, o compilador não requer que o programador capture estas exceções, embora isso seja possível.

Porém, embora estas exceções não precisem ser capturadas, elas não podem ser ignoradas. Se uma exceção de execução ocorre e o código não as

Page 234: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tratamento de Exceções

7-12

manipula, a máquina virtual irá terminar o programa e imprimir o nome da exceção e um rastro da pilha.

Exceções Verificadas (Checked exceptions)

Exceções verificadas são extensões da classe Exception. Estas exceções não são exceções de execução e são verificadas pelo compilador, que se certifica de que tais exceções serão capturadas e manipuladas em algum outro local no programa. Exceções criadas pelo programador devem estender a classe Exception.

Page 235: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tratamento de Exceções

7-13

Tratando Exceções

Quando um método utilizado pelo programa levantar uma exceção, o programador possui três opções:

- Capturar a exceção e tratá-la;

- Capturar a exceção e levantar uma exceção diferente, que será manipulada em outro local;

- Deixar a exceção passar através do método; algum manipulador deve então capturá-la em outro local.

Para identificar se um método em particular de uma classe padrão do Java pode levantar uma exceção, a documentação do JDK pode ser utilizada. Todas as classes padrão do Java são documentadas e uma parte da documentação de cada método é a lista das exceções que este método pode levantar.

Por exemplo, na classe Integer, para o método parseInt (que transforma um argumento String em um número decimal com sinal):

public static int parseInt(String s) throws NumberFormatException

Page 236: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tratamento de Exceções

7-14

Manipulando Exceções

O mecanismo para manipulação de exceções em Java é formado pelos comandos try/catch/finally.

Para manipular uma exceção, o código deve ser organizado nos seguintes blocos:

- Incluir as chamadas dos métodos que podem levantar exceções em um bloco try;

- Inserir um ou mais blocos catch, onde cada um irá capturar uma exceção em particular;

- Adicionar um bloco finally se desejado. O bloco finally é executado sempre, mesmo que nenhuma exceção tenha sido levantada.

O exemplo a seguir demonstra a sintaxe para manipular três exceções (excecaoTipo1, excecaoTipo2 e excecaoTipo3) que poderiam ser levantadas por método chamado.

Código 7-8: Tratamento de exceções utilizando os blocos try/catch/finally.

try { ... chamada do método que pode levantar exceção ... }catch (excecaoTipo1){ trata excecaoTipo1

}catch (excecaoTipo2){ trata excecaoTipo2

}catch (excecaoTipo3){ trata excecaoTipo3 }finally { ... }

Page 237: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tratamento de Exceções

7-15

O Bloco try

O comando try delimita o bloco de código que contem as chamadas para os métodos que podem levantar exceções. Se uma exceção ocorre dentro de um bloco try, esta exceção é capturada pelo manipulador de exceções apropriado associado a este bloco try.

O Bloco catch

Um bloco try pode ser seguido por zero ou mais blocos catch, que especificam como tratar os vários tipos de exceções. Cada cláusula catch é declarada com um argumento, que deve ser do tipo Throwable ou uma subclasse deste.

Quando uma exceção ocorre, o primeiro catch que possui o argumento do tipo apropriado é ativado. Este argumento deve ser o tipo da exceção do objeto ou uma superclasse da exceção, e é valido somente dentro do bloco catch.

Não é necessário que haja um bloco catch para todas as exceções possíveis. Em alguns casos, o tratamento correto é permitir que a exceção seja propagada acima e possa ser capturada por outro método que esteja na pilha.

O Bloco finally

O bloco finally contém o código responsável pela finalização do método (tais como fechamento dos arquivos, liberação dos recursos) antes que o controle seja transferido para outra parte do programa.

O código dentro deste bloco é sempre executado se uma porção do bloco try é executada, independente de como o código no bloco try é completado. Em um fluxo normal, o controle atinge o final do bloco try e passa então ao bloco finally que executa a finalização necessária.

Se o controle deixa o bloco try pelo uso de um comando return ou break, o conteúdo do bloco finally é executado antes do controle ser transferido para o novo destino.

Se uma exceção ocorre no bloco try e há um bloco catch local para manipular esta exceção, o controle é transferido para o bloco catch e posteriormente para o bloco finally. Se a exceção ocorre e não há um bloco catch para manipular a exceção, o controle é transferido para o bloco finally e então propagado para a cláusula catch mais próxima que manipula esta exceção.

É possível existir um bloco finally sem um ou mais blocos catch anteriores. Contudo, um bloco try deve sempre existir antes do bloco finally.

Page 238: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tratamento de Exceções

7-16

Manipulando Exceções: Exemplo Prático

O código a seguir apresenta um exemplo de uma classe, converteNumero, onde são capturadas duas exceções: ArrayIndexOutOfBoundsException e NumberFormatException. Esta classe converte o argumento lido no formato String para um inteiro.

Código 7-9: Exemplo de método utilizando tratamento de exceções.

Observe o código acima e descreva o que é impresso na tela nas seguintes situações:

1. A classe é chamada utilizando: C:\java ConverteNumero 38

2. A classe é chamada utilizando: C:\java ConverteNumero palavra

3. A classe é chamada utilizando: C:\java ConverteNumero

Imagine agora o exemplo acima sem o bloco catch que trata a exceção ArrayIndexOutOfBoundsException. O que aconteceria se a classe fosse chamada utilizando apenas converteNumero?

public class ConverteNumero { public static void main(String argv[]) { int num; try { System.out.println("String lida: " + argv[0]); num = Integer.parseInt(argv[0]); System.out.println("Numero: " + num); }catch (ArrayIndexOutOfBoundsException e) { System.out.println("Não foi fornecido argumento."); return; }catch (NumberFormatException e) { System.out.println("Não foi possível converter a string" + "para inteiro. Verifique a string fornecida."); }finally { System.out.println("Bloco finally."); } System.out.println("Encerrando método"); } }

Page 239: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tratamento de Exceções

7-17

Propagando Exceções

Quando uma exceção não pode ser tratada localmente ou se deseja que ela seja tratada em outro local, ela pode ser propagada para o código que chamou o método.

Para propagar uma exceção para o método acima, a exceção deve ser indicada na declaração do método chamado. Isto é feito utilizando o comando

throws.

Código 7-10: Propagação de exceções utilizando a cláusula throws.

Observe o exemplo abaixo. O método converteStringParaNumero não trata a exceção NumberFormatException localmente. Ao invés disso, a exceção passa automaticamente para o método que chamou converteStringParaNumero.

O método que chamou converteStringParaNumero pode capturar a exceção NumberFormatException ou propagar a exceção para um método acima. Caso ele deseje propagar a exceção, ele deve também conter throws NumberFormatException em sua declaração.

Código 7-11: Tratamento de exceções utilizando a cláusula throws para o contexto anterior.

tipo metodo(parametros) throws excecaoTipo1 { ... }

private void converteStringNumero(String str) throws NumberFormatException { int num; try {

System.out.println("String lida: " + str); num = Integer.parseInt(str); System.out.println("Numero: " + num); }finally { System.out.println("Bloco finally método converteStringNumero."); } System.out.println("Encerrando método converteStringNumero"); }

Page 240: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tratamento de Exceções

7-18

Lançando Exceções

O programador pode lançar exceções em seu código para indicar alguma condição anormal. Estas exceções podem ser exceções padrões do sistema ou exceções criadas pelo programador.

Ao levantar uma exceção, o que está sendo feito na realidade é a criação de um objeto e a transmissão deste para um método superior. Assim, o objeto exceção deve ser criado usando o operador new.

O exemplo a seguir apresenta um método que lança uma exceção do tipo ArrayIndexOutOfBoundsException se verificar que o índice não é válido.

Código 7-12: Antecipando uma exceção e criando a exceção correspondente.

private void testaArgumento(int indice, String vetor[]) throws ArrayIndexOutOfBoundsException { if (indice >= vetor.length) {

throw new ArrayIndexOutOfBoundsException(); } }

Page 241: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tratamento de Exceções

7-19

Criando Exceções

Para criar as suas próprias exceções, o programador deve estender a classe Exception. A classe RuntimeException não deve ser estendida, pois esta classe é utilizada para exceções comuns que não precisam ser verificadas.

O exemplo a seguir cria uma exceção chamada ExcecaoArgumentoInvalido. Esta exceção possui um único construtor que

apenas chama o construtor da superclasse.

Código 7-13: Criando uma classe do tipo Exception.

public class ExcecaoArgumentoInvalido extends Exception { public ExcecaoArgumentoInvalido (String message) { super(message); } }

Page 242: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tratamento de Exceções

7-20

Capturando Exceções e Levantando Exceções Diferentes

Quando uma exceção é levantada, o método pode capturá-la e levantar uma exceção diferente para outros métodos.

O trecho a seguir exemplifica esta situação.

Neste método, a exceção ArrayIndexOutOfBounds é capturada e uma nova exceção do tipo ExcecaoArgumentoInvalido é criada.

Código 7-14: Capturando exceções e lançando uma exceção diferente (exceção particular).

public void testaArgumento(int indice, String strvet[]) throws ExcecaoArgumentoInvalido { try { String str = strvet[indice]; } catch (ArrayIndexOutOfBoundsException e) { throw new ExcecaoArgumentoInvalido("# elementos incorretos!"); } }

Page 243: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tratamento de Exceções

7-21

Espaço para anotações

Page 244: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Tratamento de Exceções

7-22

Exercícios

1. Neste exercício você irá criar uma exceção personalizada para tratar erros de validação que podem ser então lançados quando estiver executando a aplicação e um valor incorreto for passado, por exemplo, para o método que atribui valores a um produto.

Passo 1: Crie uma classe pública chamada ValidacaoException, esta classe deve ser criada em um arquivo fonte novo e deve extender a classe RuntimeException.

Passo 2: Defina um método construtor nesta classe que possa receber uma String como parâmetro e repasse esta string para a classe pai.

Passo 3: Nas operações de modificação do atributo preco da classe Produto bem como na operação que atribui um produto a um ItemPedido faça uso desta classe para se a validação der algum erro você lançar uma exceção com uma mensagem personalizada para quem chamou esta operação.

Page 245: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Java Fundamentals

T@rgetTrust Treinamento e Tecnologia 8-1

88.. CCllaasssseess aabbssttrraattaass ee IInntteerrffaacceess

Page 246: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Classes abstratas e interfaces

8-2

Objetivos

• Criar classes abstratas

• Definir interfaces

Page 247: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Classes abstratas e interfaces

8-3

Abstração

Em Java você pode definir classes que representem, na definição de um projeto, um nível mais alto de abstração. Ao usar estas classes o projetista terá uma visão melhor de como as subclasses devem se parecer e mesmo quais métodos são obrigatórios em todas as subclasses.

Figura 8-1: Definindo a classe Produto como abstrata para não ser instanciada.

Classes Abstratas

Uma classe abstrata é simplesmente uma classe que não pode ser instanciada. Somente suas subclasses podem ser instanciadas. Por exemplo, Produto não contém detalhes suficientes para fornecer algo útil para o negócio.

Um item deve ser um CD ou um DVD. Produto serve, no entanto, como uma coleção de dados e comportamentos que são comuns a todos os itens disponíveis para alugar.

Métodos Abstratos

Métodos abstratos vão um passo além da herança padrão. Um método abstrato definido dentro de uma classe abstrata deve ser implementado pelas subclasses destas. Esta técnica permite que o projetista de classes decida exatamente quais comportamentos as subclasses devem ter.

O projetista de uma classe abstrata não consegue determinar como estes comportamentos serão implementados, mas somente que eles serão implementados.

Interfaces

Interface é a especificação de um conjunto de métodos, similares a uma classe abstrata. Além do que uma classe abstrata pode oferecer, uma interface pode efetivamente permitir herança múltipla.

Uma classe pode implementar um número ilimitado de interfaces, mas pode estender somente uma única superclasse.

Page 248: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Classes abstratas e interfaces

8-4

Definindo classes abstratas

Java fornece a palavra reservada abstract que indica que uma classe é abstrata. Por exemplo, a classe Produto no exemplo abaixo foi declarada como

sendo abstrata:

Figura 8-2: Definições das classes Produto, DVD e CD. Herança e Abstração da classe Produto.

Produto é declarado como uma classe abstrata porque não possui informação ou comportamento suficientes para representar um objeto autônomo.

O usuário não deveria ser capaz de criar objetos Produto, porque Produto é apenas uma classe parcial e intermediária. Produto existe somente para que possa ser estendida por classes mais especializadas, tais como CD ou DVD.

O que acontece se você tentar instanciar uma classe abstrata?

Código 8-1: Erro de compilação na criação de uma instância de uma classe abstrata.

Se você tentar criar um objeto Produto em seu programa, o compilador acusará um erro. O usuário pode criar somente objetos de subclasses concretas:

Código 8-2: Criação com sucesso de instâncias especializadas.

O modificador abstract pode ser aplicado somente a classes e métodos. Classes abstratas provem um modo de adiar a implementação de métodos para

Produto produto = new Produto(); // Erro de compilação

CD cd = new CD(); // Herdando Produto DVD dvd = new DVD(); // Herdando Produto

Page 249: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Classes abstratas e interfaces

8-5

subclasses. Uma classe abstrata não pode ser instanciada, ou seja, não podemos chamar seus construtores.

Page 250: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Classes abstratas e interfaces

8-6

Métodos Abstratos

Ao projetar uma hierarquia de classes, há provavelmente algumas operações que todas as classes deverão ter, cada qual de sua própria maneira. Por exemplo, em um negócio de aluguel de fitas, o vendendo deve saber se um item pode ser alugado ou não.

Cada tipo de item, entretanto, determina se pode ser alugado de uma maneira específica.

Para representar este conceito em Java, o método “este item pode ser importado” é definido na classe Produto. Entretanto, não há uma implementação sensata para este método em Produto, porque cada tipo de item tem suas próprias exigências.

Uma abordagem, seria deixar o método vazio na classe Produto:

Código 8-4: Definindo métodos concretaos em classes abstratas.

Esta abordagem não é boa o suficiente porque não força cada uma das subclasses concretas a sobrescrever o método. Suponha, por exemplo, que a classe DVD se esqueça de sobrescrever o método isImportado(), o que aconteceria se o usuário chamasse este método a partir de uma referência para DVD?

O método isImportado() definido em Produto seria chamado e retornaria true. Este não é o resultado desejado. A solução é declarar o método como abstrato, como mostrado logo a seguir.

public abstract class Produto { public boolean isImportado() { return true; } }

Page 251: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Classes abstratas e interfaces

8-7

Definindo métodos abstratos

Para declarar um método abstrato em Java, você deve colocar antes do nome do método a palavra reservada abstract. Veja o exemplo:

Código 8-5: Definindo métodos abstratos em classes abstratas.

Ao declarar um método abstrato, você deve fornecer somente a assinatura do método, que compreende: o nome do método, a lista de parâmetros esperados e o tipo de retorno. Você não fornece um corpo para o método.

Cada subclasse concreta deverá sobrescrever este método e fornecer o seu próprio corpo.

Agora que o método é declarado abstrato, todas as subclasses devem fornecer uma implementação para ele.

Subclasses abstratas podem conter métodos que não são declarados abstratos. Estes métodos podem ser sobrescritos pelas subclasses, mas isto não pé necessariamente obrigatório.

public abstract class Produto { public abstract boolean isImportado(); }

Page 252: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Classes abstratas e interfaces

8-8

Interfaces

Uma interface é similar a uma classe abstrata, exceto que ela não possui nenhum método concreto ou variáveis de instância. É apenas uma coleção de declarações de métodos abstratos e constantes isto é, variáveis declaradas como static public final.

Uma interface é como um contrato que a subclasse deve obedecer.

Qualquer classe que implemente uma interface deve implementar todos os métodos especificados na interface. Uma classe pode implementar muitas interfaces, mas pode estender apenas uma única classe. Java não suporta herança múltipla, mas permite a implementação de múltiplas interfaces.

Como já foi dito anteriormente, CD herda todos os atributos e comportamentos de Produto. Além disto, deve fornecer implementação para cada um dos métodos definidos em cada interface que implementar.

Estes métodos podem ser usados por outras classes para implementar comportamentos específicos como, por exemplo, uma rotina de ordenamento.

Page 253: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Classes abstratas e interfaces

8-9

Exemplos de interfaces

Interfaces descrevem um aspecto de comportamento que muitas classes possuem. O nome de uma interface é geralmente um comportamento como: Compra, Venda, etc. Difere, portanto, do nome de uma classe, que é usualmente um substantivo, como cliente ou produto.

A interface java.sql.Connection possui os métodos a seguir:

- void commit()

- void rollback()

- void close()

- void clearWarnings()

- Statement createStatement()

- void setAutoCommit(boolean)

- boolean isClosed()

Qualquer classe que precise trabalhar com conexão de bando de dados pode implementar a interface Connection.

As classes que implementam uma interface podem ser completamente distintas e não ter uma nada a ver com as demais.

A única coisa que devem ter necessariamente em comum é a necessidade de todas serem móveis.

Page 254: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Classes abstratas e interfaces

8-10

Definindo Interfaces

Você pode definir uma interface usando a palavra reservada interface. Todos os métodos especificados em uma interface são implicitamente públicos e abstratos (public e abstract). Quaisquer variáveis definidas em uma interface são implicitamente públicas, estáticas e constantes (public, static e final).

Código 8-6: A interface Conncetion do pacote java.sql.

Portanto, a definição acima equivaleria à seguinte definição:

Código 8-7: A interface Conncetion do pacote java.sql equivalente.

Porque os métodos de interface são implicitamente públicos e abstratos é prática geralmente aceita não especificar estes modificadores de acesso. O mesmo é verdade para variáveis.

Como são implicitamente públicas, estáticas e finais, geralmente estes modificadores não são especificados. Cada interface pode ser representada em um arquivo Java separado com o nome da interface. (neste caso poderíamos criar um arquivo chamado Connection.java do pacote java.sql)

public interface Connection { public void commit(); public void rollback(); public void close(); public void clearWarnings(); public Statement createStatement(); public void setAutoCommit(boolean b); public boolean isClosed(); // entre outros métodos ... }

public interface Connection { public abstract void commit(); public abstract void rollback(); public abstract void close(); public abstract void clearWarnings(); public abstract Statement createStatement(); public abstract void setAutoCommit(boolean b); public abstract boolean isClosed(); // entre outros métodos ... }

Page 255: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Classes abstratas e interfaces

8-11

Implementando Interfaces

O exemplo abaixo mostra o exemplo da classe OracleConn que implementa a interface Conncetion. OracleConn deve implementar todos os métodos de todas as interfaces que ele declare implementar (interfaces presentes na cláusula implements).

Neste caso, OracleConn deve implementar os métodos contidos na interface Connection.

Código 8-8: A classe OracleConn deve implementar TODOS os métodos da interface Conncetion.

Uma classe pode implementar mais de uma interface se ela desejar, bastando para tal especificar uma lista de interfaces separadas por vírgula.

Considere o seguinte exemplo:

Código 8-9: A classe Aplicacao pode implementar mais de uma interface.

Aqui, Aplicacao implementa duas interfaces: InterfaceI e InterfaceII. Isto significa que a classe Aplicacao deve implementar todos os métodos declarados em InterfaceI e InterfaceII. A classe Aplicacao terá o comportamento definido nas duas interfaces.

public class OracleConn implements Connection { public void commit() { //... código } public void rollback() { //... código } }

public class Aplicacao extends JFrame implements InterfaceI, InterfaceII { }

Page 256: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Classes abstratas e interfaces

8-12

Espaço para anotações

Page 257: Java SE Em Portugues Excelente Apostila Curso Completo de Introdução a Java SE

Classes abstratas e interfaces

8-13

Exercícios

1. Crie uma interface para representar uma fila de impressão Passo 1: Declare uma interface em um arquivo novo com os seguintes comportamentos: boolean imprimir() void parar() boolean remover(Documento doc) void refresh() void pausa()

Passo 2: Crie uma classe para implementar esta fila de impressão e codifique as operações nela 2. Trabalhando com classes abstratas Passo 1: Torne a classe Produto abstrata adicionando a palavra reservada abstract na assinatura da classe. Passo 2: Tente criar um objeto desta classe agora. É possível? Passo 3: Transforme a operação que retorna o preço abstrata uma vez que a forma de calcular o preço irá depender de cada uma das subclasses.