SebentaJava

140

Transcript of SebentaJava

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 1

Índice de Matérias 1 - Conceitos Básicos de Ciências da Computação.................................................................................................... 4

1.1 - Motivação ............................................................................................................................................................ 4 1.2 - Resolução de Problemas .................................................................................................................................... 4

1.2.1 - Criação de Algoritmos ................................................................................................................................. 5 1.2.2 - Técnicas de Descrição de Algoritmos ......................................................................................................... 7

1.3 - Do Algoritmo ao Programa ................................................................................................................................ 15 1.3.1 - Representação Digital da Informação ....................................................................................................... 15 1.3.2 - Componentes de um Computador ............................................................................................................ 16

1.4 - Linguagens de Programação ............................................................................................................................ 17 1.4.1 - Tradução de Linguagens de Programação............................................................................................... 17

1.5 - A Linguagem Java............................................................................................................................................. 18 1.5.1 - Compilar um Programa em Java............................................................................................................... 18 1.5.2 - Exemplo de um Programa em Java .......................................................................................................... 19

1.6 - Exercícios Práticos ............................................................................................................................................ 19 2 - Introdução as noções de Classe e Objecto.......................................................................................................... 21

2.1 - Conceito de Objecto e Classe ........................................................................................................................... 21 2.2 - Exercícios .......................................................................................................................................................... 25

3 - Conceitos básicos de programação em Java....................................................................................................... 27 3.1 - Identificadores ................................................................................................................................................... 27 3.2 - Palavras Reservadas ........................................................................................................................................ 27 3.3 - Símbolos e Valores ........................................................................................................................................... 28 3.4 - Variáveis............................................................................................................................................................ 28

3.4.1 - Variáveis de Instância: Atributos ............................................................................................................... 29 3.5 - Tipos de Dados ................................................................................................................................................. 29

3.5.1 - Tipos de Dados Primitivos......................................................................................................................... 30 3.5.2 - Tipos de Dados Referenciados ................................................................................................................. 33

3.6 - Operadores e Expressões................................................................................................................................. 35 3.6.1 - Operadores de Atribuição ......................................................................................................................... 35 3.6.2 - Operadores Aritméticos............................................................................................................................. 35 3.6.3 - Operadores Lógicos .................................................................................................................................. 37 3.6.4 - Operadores Relacionais............................................................................................................................ 38 3.6.5 - Expressões................................................................................................................................................ 38

3.7 - Métodos............................................................................................................................................................. 39 3.7.1 - Método construtor sem argumentos.......................................................................................................... 40 3.7.2 - Invocação de métodos e passagem de parâmetros ................................................................................. 41 3.7.3 - Métodos construtores com argumentos .................................................................................................... 45 3.7.4 - Métodos selectores ................................................................................................................................... 47 3.7.5 - Métodos modificadores ............................................................................................................................. 48

3.8 - Estrutura de Aplicações em JAVA..................................................................................................................... 49 3.8.1 - Estrutura do programa principal ................................................................................................................ 49 3.8.2 - Visibilidade das Variáveis.......................................................................................................................... 50 3.8.3 - Entrada e Saída de Dados ........................................................................................................................ 50 3.8.4 - Definição de Novas Classes ..................................................................................................................... 53 3.8.5 - Utilização de classes existentes em JAVA................................................................................................ 54 3.8.6 - Comentários .............................................................................................................................................. 56 3.8.7 - Paragrafação / Indentação ........................................................................................................................ 56

3.9 - Exercícios Práticos ............................................................................................................................................ 57 4 - Instruções de Controlo ......................................................................................................................................... 58

4.1 - Selecção............................................................................................................................................................ 58 4.1.1 - Selecção Simples: if............................................................................................................................... 58 4.1.2 - Selecção Em Alternativa: if-else....................................................................................................... 60

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 2

4.1.3 - Selecção Múltipla: switch - case .................................................................................................. 65 4.2 - Repetição .......................................................................................................................................................... 68

4.2.1 - Instrução de Repetição while ............................................................................................................... 68 4.2.2 - Instrução de Repetição do-while ....................................................................................................... 70 4.2.3 - Instrução de Repetição for .................................................................................................................... 72

4.3 - Exercícios Práticos ............................................................................................................................................ 76 5 - Tópicos Avançados de Classes ........................................................................................................................... 82

5.1 - Variáveis de Instância e variáveis de Classe .................................................................................................... 82 5.2 - Modificadores de visibilidade............................................................................................................................. 85 5.3 - Encapsulamento................................................................................................................................................ 85 5.4 - O Operador de Auto-Referenciação this ...................................................................................................... 85 5.5 - Passagem por Parâmetros Referenciados........................................................................................................ 86 5.6 - Sobrecarga de Métodos .................................................................................................................................... 87 5.7 - Exercícios Práticos ............................................................................................................................................ 88

6 - Tabelas................................................................................................................................................................. 90 6.1 - Motivação .......................................................................................................................................................... 90 6.2 - Tabela Unidimensional ...................................................................................................................................... 92

6.2.1 - Introdução ................................................................................................................................................. 92 6.2.2 - Passos para utilizar uma tabela ................................................................................................................ 92

6.3 - Tabelas de Objectos.......................................................................................................................................... 96 6.4 - Passagem de tabelas como parâmetros de métodos ..................................................................................... 107 6.5 - Tabela Multidimensional.................................................................................................................................. 108 6.6 - Classe Vector .................................................................................................................................................. 110

6.6.1 - Introdução ............................................................................................................................................... 110 6.6.2 - Alguns métodos da classe Vector...................................................................................................... 110

6.7 - Exercícios Práticos .......................................................................................................................................... 111 7 - Algoritmos de Procura/Pesquisa ........................................................................................................................ 114

7.1 - Introdução........................................................................................................................................................ 114 7.2 - Procura Sequencial ......................................................................................................................................... 114

7.2.1 - Simples.................................................................................................................................................... 114 7.2.2 - Com Sentinela......................................................................................................................................... 116

7.3 - Procura Binária................................................................................................................................................ 117 7.4 - Exercícios práticos .......................................................................................................................................... 119

8 - Algoritmos de Ordenação................................................................................................................................... 121 8.1 - Introdução........................................................................................................................................................ 121 8.2 - BubbleSort....................................................................................................................................................... 122 8.3 - ShellSort .......................................................................................................................................................... 124 8.4 - Ordenação por selecção ................................................................................................................................. 126 8.5 - Algoritmo QuickSort......................................................................................................................................... 127 8.6 - Exercícios práticos .......................................................................................................................................... 129

9 - Recursividade..................................................................................................................................................... 130 9.1 - Definições........................................................................................................................................................ 130 9.2 - Exercícios práticos .......................................................................................................................................... 132

10 - Anexo I – Exemplo Introdutório em Java ...................................................................................................... 134 11 - Anexo II – Glossário ...................................................................................................................................... 136 12 - Anexo III - Bibliografia ................................................................................................................................... 138

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 3

Nota: Ao longo da leitura deste documento, sempre que não entender o significado de determinado termo, por favor dirija-se ao glossário que é apresentado em anexo para descobrir uma possível definição para o mesmo. Caso não esteja lá definida a palavra que procura, não hesite em questionar os colegas ou professores para melhor ficar esclarecido. Ao notificar o professor estará também a contribuir para melhorias futuras no documento, pois novas palavras poderão ser adicionadas ao glossário que possivelmente esclarecerão outros colegas com dúvidas semelhantes à sua. Este documento, para além de ter sido elaborado pelos professores já mencionados, conta com a participação dos docentes da cadeira de IP dos anos lectivos de 2000/2001 até 2004/2005, visto terem sido utilizados os respectivos acetatos como referência para alguns dos conteúdos aqui utilizados. A sebenta do ano lectivo 2004/2005 foi reestruturada e melhorada.

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 4

1 - Conceitos Básicos de Ciências da Computação

1.1 - Motivação

Nas sociedades modernas todos os sectores de actividade dependem directa ou indirectamente do apoio dos computadores. O funcionamento dos computadores depende da conjunção do Hardware, componentes físicos, e do Software, instruções que os computadores devem executar. Pode dizer-se que os programas fornecem conhecimentos e estratégias de resolução de problemas. A programação é a “arte” de analisar um problema e encontrar uma sequência de acções (um algoritmo) capaz de o resolver correctamente.

1.2 - Resolução de Problemas

O objectivo de um programador, quando escreve um programa, é o de resolver um ou mais problemas. Para que se possa resolver um problema é necessário que seja primeiramente encontrada uma maneira de o descrever de forma clara e precisa. É necessário que encontremos uma sequência de passos que permitam que o problema possa ser resolvido de maneira automática e repetitiva. Esta sequência de passos é chamada de Algoritmo. Assim, podemos afirmar que o passo fundamental na criação de um programa é a definição de um algoritmo isto é, a forma como a partir de um problema se consegue obter a solução. Contrariamente ao que se possa pensar, na maioria das vezes, a principal dificuldade não reside na sintaxe1 ou na semântica2 da linguagem de programação utilizada, mas sim na procura de soluções para o problema em causa. Um algoritmo pode ser definido como um conjunto finito de instruções bem definidas e não ambíguas, que executadas por uma determinada ordem resolvem um problema. Para que se possa encontrar uma boa solução para um problema, é necessário começar pela sua compreensão. Em seguida, o problema deve ser analisado no sentido de procurar soluções para o mesmo. Quando se faz a análise de um problema é importante considerar três componentes:

estado inicial, isto é quais os dados de entrada do problema; a transformação, que especifica os passos necessários para transformar o estado inicial no estado final; estado final, ou seja, o que se pretende obter como resultado.

Muitos dos erros dos programadores são causa de uma deficiente compreensão e análise do problema. A resolução de problemas é uma tarefa para a qual não há receitas nem fórmulas, pois cada problema é um caso diferente, tal como podem ser inúmeras as soluções que o resolvem. Umas serão mais correctas ou terão melhor desempenho que outras, umas ainda serão mais ou menos exaustivas; cabe-nos a nós, como programadores, saber averiguar qual das soluções encontradas se adequa melhor às necessidades da tarefa que temos em mãos. Exemplo: Vamos supor que temos como tarefa resolver o problema da confecção de um bolo. Uma receita não é mais do que uma descrição de passos ou acções que fazem a combinação de um conjunto de ingredientes com vista a obter um produto final (bolo).

1 Sintaxe de uma linguagem é o conjunto de regras que define as relações válidas entre componentes da linguagem. 2 Semântica de uma linguagem define o significado de cada frase da linguagem.

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 5

Analisando tudo o que é necessário para cumprir essa tarefa e tendo em conta os passos atrás mencionados, quais são os passos a seguir? Estado inicial: ingredientes (respectivas quantidades) Transformação: processo de confecção do bolo (Algoritmo)

1. Misturar ingredientes 1.1 Bater a margarina e o açúcar até obter um creme; 1.2 Adicionar os ovos 1.3 Juntar a farinha e o fermento; 1.4 Colocar a massa numa forma 2. Cozinhar o bolo 2.1 Aquecer o forno à temperatura desejada 2.2 Colocar no forno e esperar que o bolo esteja cozido Estado final: um bolo

Afinal não é só na programação de computadores que podemos aplicar algum método ou tipo de raciocínio para resolver problemas! Com este exemplo vimos aplicada a um caso da vida quotidiana exactamente a mesma ordem de pensamento que iremos seguir daqui por diante na implementação de programas de computadores.

1.2.1 - Criação de Algoritmos

A criação de algoritmos é fundamental no desenvolvimento de programas de computador. Quando se trata de programas complexos, surgem dificuldades adicionais devidas há quantidades de aspectos que é necessário considerar no momento. A complexidade tanto pode ser gerada pela dimensão, como pela dificuldade do problema a resolver.

1.2.1.1 - Abordagens Top-Down e Bottom-Up Existem duas abordagens para a resolução de problemas. Uma, a mais utilizada, é a conhecida como “abordagem do topo para a base” (abordagem Top-Down), por partir de um problema geral e procurar chegar aos detalhes. Nesta abordagem o problema complexo é dividido em problemas mais simples e procura-se soluções para esses problemas mais simples. Existe também a abordagem contrária, apelidade de Bottom-Up que parte da base para o topo, ou seja, partindo de problemas pequenos, visualizar a solução para algo mais amplo e mais genérico. Pode até utilizar-se um misto destas duas abordagens, desde que no fim consigamos atingir uma boa solução para o problema. Em qualquer uma delas está inerente um conceito que é a base de resolução de qualquer problema: a divisão em elementos de solução mais simples, que trabalhando em conjunto nos fazem chegar à solução que nos interessa. Independentemente do sentido em que procuramos a solução, estamos sempre a utilizar uma técnica que se chama “Divide and Conquer” , ou seja, Dividir para Conquistar. Ninguém ganha uma corrida só porque decide ganhar, tem de correr as etapas todas uma por uma com o objectivo de no fim ter conseguido uma média de tempos inferior à dos outros corredores! Exemplo: Fazer sumo de laranja Aplicando o método anteriormente descrito, significa que temos de dividir um problema em partes menores (ou subproblemas) de modo a que seja mais fácil a sua resolução

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 6

Algoritmo: Lavar a laranja Partir a laranja ao meio Espremer a laranja Filtrar o sumo Servir o sumo O que se pode destacar com este exemplo é que cada passo é completado antes que o próximo comece. Como por exemplo, é impossível ouvir rádio sem primeiro o ligar.

1.2.1.2 - Passos para elaboração de um algoritmo Quando pretendemos escrever um algoritmo é importante que se sigam um conjunto de passos:

Compreender o problema Identificar os dados de entrada Identificar os dados de saída Determinar o que é necessário para transformar dados de entrada em dados de saída, isto é, deve-se descrever todas as transformações necessárias para resolver o problema, fazendo-o em termos que possam ser executáveis pelo computador

- usar a estratégia de dividir em problemas mais pequenos - observar regras e limitações - identificar todas as acções a realizar - eliminar ambiguidades (qualquer pessoa que o execute obtém os mesmos resultados)

Construir o algoritmo, tendo em consideração que: -Para um mesmo conjunto de dados deve produzir sempre os mesmos resultados (se com os

mesmos ingredientes, nas mesmas quantidades tivéssemos bolos diferentes algo de errado se tinha passado)

- Produzir resultados correctos, qualquer que seja o conjunto de dados legítimos utilizado. Testar o algoritmo Executar o algoritmo

No entanto, quando se concebem algoritmos para serem transformados em programas é importante exprimi-los utilizando acções que o computador seja capaz de executar:

Receber e fornecer informação Guardar informação para posterior utilização Operações aritméticas Operações lógicas Escolher entre várias acções (selecção) Repetir um grupo de acções (repetição)

Outro aspecto importante é que os nossos algoritmos vão ter que manipular valores, estes têm que ser guardados em algum lugar. Para tal utilizam-se variáveis. Uma variável é um lugar na memória do computador onde podemos colocar um valor, ou consultar o valor que lá está. Cada variável é identificada por um nome. Exemplo: Elaborar um algoritmo que calcule a área total das paredes de uma caixa de secção rectangular a partir das suas dimensões. Identificação das variáveis que o algoritmo vai manipular:

Dados de entrada: comprimento -> comp, largura -> largura, altura -> altura Valores intermédias: area_base, area_lateral1, area_lateral2

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 7

Dados de saida: área da caixa -> area_caixa

Algoritmo: 1. Introdução dos valores iniciais

1.1. Pedir comprimento da caixa 1.2. Ler comp 1.3. Pedir largura da caixa 1.4. Ler largura 1.5. Pedir altura da caixa 1.6. Ler altura

2. Transformação 2.1. area_base = comp * largura 2.2. area_lateral1 = comp * altura 2.3. area_lateral2 = largura * altura 2.4. area_caixa = 2 * area_base + 2 * area_lateral1 + 2 * area_lateral2

3. Apresentação dos resultados 3.1. Escrever area_caixa

1.2.2 - Técnicas de Descrição de Algoritmos

Os algoritmos não são directamente executáveis pelo computador, a forma como são descritos é um pouco livre, ainda que deva ser suficientemente exacta para que não haja qualquer ambiguidade. Existem várias técnicas para a descrição de algoritmos. Uma maneira de descrever algoritmos é usando linguagem natural, em que os algoritmos são expressos directamente em linguagem natural (isto é, o português como no exemplo do bolo). Outra maneira é usando pseudocódigo (exemplo calculo da área). O pseudocódigo é um código de escrita em que se utilizam termos convencionais para indicar as instruções do programa; esses termos são geralmente um misto de palavras da nossa linguagem natural com palavras e notações típicas das linguagens de programação. A utilização de pseudocódigo permite ao programador expressar as suas ideias sem ter de se preocupar com a sintaxe da linguagem de programação. Os algoritmos podem também ser descritos utilizando fluxogramas. Os fluxogramas são diagramas representativos do fluxo de acções de um programa, através de símbolos, que representam os diferentes tipos de acções e seu encadeamento na sequência do programa (ver figura abaixo).

Figura 1. Representação gráfica de um algoritmo.

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 8

Processamento em geral

Leitura/Escrita de Dados

Início/Fim de processamento

Linha de fluxo

Decisão condicional

Escolha múltipla

Subprograma

Figura 2. Principais símbolos utilizados nos fluxogramas.

Actualmente os fluxogramas não são efectivamente muito utilizados. No entanto, talvez possam ser úteis para ajudar a visualizar melhor determinadas estruturas típicas de programação. Mas, para representar programas de média e grande extensão, tornam-se difíceis de concretizar. Exemplo Elaborar um algoritmo que calcule o quadrado de um número. Pseudocódigo Início Pedir valor de a Ler a Calcular quadrado de a result = (a*a) Escrever “O quadrado é:” result Fim

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 9

Fluxograma

1.2.2.1 - Estruturas de controlo Uma estrutura de controlo é a unidade básica da lógica de programação. Podemos dizer que qualquer programa pode ser construído através da combinação de 3 estruturas básicas: sequência, selecção e repetição. Numa sequência é processado um conjunto de acções (ou instruções) em série. O conjunto de acções é executado exactamente pela ordem em que as instruções estão indicadas, não havendo qualquer possibilidade de alterar a ordem de processamento dessas acções.

Início

Ler a

Escrever “O quadrado é:”

result

Fim

result = a*a

Pedir a

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 10

Uma estrutura de selecção (ou decisão) é uma estrutura que permite, com base numa condição, decidir sobre a execução ou não de determinada acção ou optar entre duas alternativas expressas. Ou seja, o processo segue por uma de duas vias, dependendo do valor lógico (verdadeiro ou falso) da expressão que é avaliada no início da estrutura. Exemplo Elaborar um algoritmo que calcule o zero da equação ax+b=0. Pseudocódigo Início Pedir valor a Ler a Pedir valor b Ler b Se a ≠ 0 então Calcular o valor de x (ax+b=0) Escrever valor de x Senão Escrever “Não há zero” Fim

Expressão Verdadeiro Falso Verdadeiro Falso Expressão

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 11

Fluxograma Exemplo Elaborar um algoritmo que verifique qual o maior de dois números.

Início

Ler a

Ler b

Início

Pedir a

Ler a

a ≠ 0

Escrever valor de x

Sim

Não

Fim

x= - b/a

Escrever “Não Existe zero.”

a ≠ 0

Escrever valor de x

Sim

Não

Fim

x= - b/a

Escrever “Não Existe zero.”

Ler a

Ler b

Pedir b

Ler b

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 12

Pseudocódigo: Início Pedir “Introduza dois números” Ler valor 1 Ler valor 2 Se valor1 > valor 2 então Escreve valor1 “é maior” Senão Se valor1 < valor 2 então Escreve valor2 “é maior” Senão Escreve “valores iguais” Fim_Se Fim_Se Fim Fluxograma:

Início

Ler valor 1

Ler valor 2

valor 1 > valor 2

Escrever valor 1 é maior

Sim

valor 1 < valor 2

Sim

Não

Escrever valor 2 é maior

Escrever valores iguais

Não

Fim

Ler a Pedir dois valores

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 13

Por último falta falar das estruturas de repetição (também conhecidas por ciclos). Neste caso também é necessário tomar a decisão com base no valor lógico de uma expressão. No entanto, a mesma acção é expressa repetidamente enquanto o resultado da expressão lógica se mantiver verdadeiro. Nas estruturas de repetição o teste da expressão lógica pode preceder a acção ou pode suceder a acção, isto é na primeira situação a acção só é realizada se a condição tiver o valor lógico verdadeira, no segundo caso a acção é sempre realizada qualquer que seja o valor lógico da expressão pois este só é verificado depois da acção ter sido realizada. Esta última estrutura de repetição é idêntica às duas anteriores. A diferença é que logo à partida é especificado o número de ciclos (ou iterações) que serão efectuados, isto é o número de vezes que a acção é realizada. Estas estruturas apresentam grandes vantagens para a programação em termos de economia de escrita de código, uma vez que, com um determinado número de instruções, pode repetir-se um conjunto de acções um determinado número de vezes ou enquanto se quiser, mediante uma expressão de controlo.

Expressão Falso

Expressão Verdadeiro

Verdadeiro

Falso

Falso

Expressão Verdadeiro

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 14

Exemplo Elaborar um algoritmo em que um utilizador introduz um número e outro utilizador vai tentar advinhar esse número, introduzindo números até a acertar. O segundo utilizador só para de introduzir número quando acertar.

Algoritmo

Fluxograma

Início Pedir a Ler a (número a acertar) Repetir Pedir b Ler b Até que a = 0 Escrever “Acertou” Fim

Início

Pedir b

a = b

Sim

Não

Ler b

Escrever “Acertou”

Sim

Não

Fim

Pedir a

Ler a

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 15

Não existe consenso entre os especialistas sobre qual é a melhor maneira de representar um algoritmo. Actualmente a maneira mais comum de representar é através de pseudocódigo. A utilização de pseudocódigo tem a vantagem de podermos utilizar um texto escrito dessa forma como base para a escrita de um programa, não apenas numa determinada linguagem de programação, mas em qualquer outra, sem ter de se elaborar um novo algoritmo. Outra vantagem da escrita de algoritmos em pseudocódigo é que esta forma de abordagem presta-se a uma aproximação sucessiva à versão final do programa, ou seja, pode-se ir progredindo por fases, revendo o pseudocódigo e substituindo-o progressivamente por termos e sinais próprios da linguagem de programação.

1.3 - Do Algoritmo ao Programa

1.3.1 - Representação Digital da Informação

Os computadores armazenam e processam toda a informação, utilizando o sistema de numeração Binário. O sistema de numeração binário é um sistema de dois estados. A unidade básica deste sistema é o bit, que pode assumir apenas dois estados distintos, representados pelos valores 0 e 1. Observemos a tabela seguinte:

Como podemos verificar na tabela N bits representam 2N itens distintos. Quer-se com isto dizer, com 1 bit conseguimos representar 21 = 2 números, com 2 bits conseguimos representar 22 = 4 números distintos, com 3 bits representam-se 23 = 8 números, e assim sucessivamente. A conversão de números do sistema binário para o sistema decimal também é simples, vejamos o seguinte exemplo: 111 = 1*22 + 1*21 + 1*20 = 7 101 = 1*22 + 0*21 + 1*20 = 5 Do sistema decimal para o sistema binário, basta fazer divisões sucessivas por dois e aproveitar o resto da divisão inteira: 7 / 2 = 3 e o resto da divisão é 1 3 / 2 = 1 e o resto da divisão é 1 1 / 2 = 0 e o resto da divisão é 1 Os computadores armazenam dados em séries de 8 bits, denominados bytes. Consoante o número de bits ou de bytes podemos dar nomes diferentes às unidades (à semelhança do que acontece no sistema métrico com metros, decímetros, centímetros, etc.). Vejamos a tabela seguinte:

Unidade Conversão Símbolo SI

1 bit N/A b 1 byte 8 bit B 1 Kilobyte 1024 byte KB 1 Megabyte 1024 Kilobyte MB 1 Gigabyte 1024 Megabyte GB

Num. Decimal 1 bit 2 bits 3 bits 0 0 00 000 1 1 01 001 2 10 010 3 11 011 4 100 5 101 6 110 7 111 ... ... ... ...

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 16

Existem outros sistemas de numeração para além do decimal e do binário, tais como o octal e o hexadecimal, por exemplo.

1.3.2 - Componentes de um Computador

Um computador tem uma parte física (hardware), constituída pelo monitor, teclado, rato, memória etc., e uma parte não física (software), constituídas pelos programas.

Figura 3. Componentes de um computador. O componente mais importante do computador é a unidade central (CPU – Central Processing Unit). A função básica do CPU é obter, interpretar e executar instruções, uma de cada vez. Esta unidade executa continuamente um ciclo que consiste nos passos seguintes:

• Aquisição (obtenção de uma instrução) • Descodificação (determinação do tipo de instrução) • Execução (execução da instrução).

O CPU é constituído por:

Figura 4. Componentes da CPU.

Unidade Controle Determina a próxima instrução a ser executada (controla todos os passos do processamento)

Unidade Aritmética/Lógica Efectua cálculos (adição, subtracção e outras operações aritméticas, bem como a comparação de valores) e toma decisões

Registos Pequeno número de registos com grande velocidade de acesso, para armazenamento de resultados temporários

Periféricos De Entrada

Unidade Central de Processamento (CPU)

Periféricos De Saída

Memória Principal

Memória Secundária

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 17

Outro elemento fundamental é a memória central, também conhecida por RAM (Random Access Memory). É uma área de armazenamento de informação que apresenta as seguintes características:

Perde o conteúdo quando se desliga o computador – memória volátil; Pode ser imaginada como sucessão de células (ver figura abaixo); Cada célula de memória armazena um único valor; Quando se escreve um novo valor numa célula de memória, perde-se o valor que anteriormente lá estava; A capacidade da memória é expressa no número de bytes que ela consegue armazenar: kilobytes (KB –

1024 bytes), megabytes (MB – 1024 KB ou 1024000 bytes), gigabytes (GB – 1024 MB ou 1024000000 bytes)

Supondo que tínhamos uma memória RAM de 1MB, a sua representação gráfica poderia ser a seguinte (em que os números abaixo da tabela de células representam os índices que identificam cada célula. Célula número 1, 2, ... 256, etc):

z a 12 x 0 1 2 3 ... 256 ... 512 ... 1024

Figura 5. Representação gráfica da memória central de um computador (RAM) Para além da CPU e da memória central, existem diversos tipos de dispositivos que permitem a comunicação entre o computador e o utilizador, como por exemplo:

• dispositivos de entrada: teclado, rato; • dispositivos de saída: monitor, impressora; • dispositivos de entrada/saída: modem.

O armazenamento permanente da informação é conseguido em dispositivos de armazenamento secundário:

Armazém de dados ligado à memória principal Mantém o conteúdo mesmo com o computador desligado – memória não volátil – armazenamento

permanente (também se diz persistente) da informação Estes dispositivos de armazenamento secundário persistente são os Discos rígidos, disquetes, CD-Roms, DVDs, FlashDrives, cartões de memória usados nas máquinas fotográficas digitais, entre outros.

1.4 - Linguagens de Programação

Para que um computador possa executar determinada tarefa, é necessário que lhe seja fornecido um programa. Os programas são escritos utilizando linguagens de programação. Há diversos níveis de linguagem de acordo com as afinidades que apresentam com as linguagens humanas:

Linguagens Máquina: são utilizadas para comandar directamente as acções do computador. As instruções são constituídas por 0s e 1s, e manipulam directamente entidades dentro do computador.

Linguagens Assembly: são linguagens com características semelhantes às das de máquina, diferindo apenas por usarem nomes simbólicos em vez de sequências de 0s e 1s.

Linguagens de Alto Nível: são linguagens mais próximas das linguagens humanas e, por isso, são mais fáceis de utilizar do que as outras. Há muitas linguagens que se podem incluir nesta categoria: C, Pascal, Lisp, Prolog, C++ e Java.

1.4.1 - Tradução de Linguagens de Programação

Um programa é fornecido ao computador para que este o possa executar. No entanto, os computadores só entendem linguagem máquina, pelo que é necessário proceder à tradução do programa. Para efectuar essa tradução utilizamos

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 18

compiladores. Os compiladores são programas que fazem a tradução do código fonte (escrito numa linguagem de alto nível) para código executável (em linguagem máquina). A primeira função dos compiladores é verificar se o código fonte que lhe é fornecido cumpre as regras sintácticas da linguagem em causa e assinalar os erros que eventualmente existam, denominados por erros de compilação. Aos erros que ocorrem durante a execução do programa e que não podem ser detectados durante a compilação dá-se o nome de erros de execução. Um programa sem erros de compilação não significa necessariamente que funcione como era desejado. Pode ter erros semânticos (ou seja, erros lógicos, derivados de um raciocínio errado que levou a uma solução também incorrecta). Neste caso, teremos de proceder a uma revisão do código e novos testes para que os erros sejam resolvidos.

1.5 - A Linguagem Java

JAVA é uma linguagem de programação orientada a objectos, desenvolvida pela Sun Microsystems. Esta linguagem resultou da ideia de criar uma linguagem que pudesse ser executada em qualquer tipo de computador.

1.5.1 - Compilar um Programa em Java

Um dos objectivos principais do desenvolvimento do Java era a possibilidade de um programa escrito nesta linguagem ser executado em qualquer tipo de computador sem ter de ser alterado ou compilado novamente. No entanto, este objectivo não pode ser atingido com a utilização de compiladores tradicionais. Este problema fica resolvido considerando um computador virtual que se imagina capaz de executar um código constituído por instruções simples. O compilador Java não gera código executável mais sim bytecode, um código que é independente do computador em que seja executado. Esse código tem de ser interpretado pela chamada Máquina Virtual Java, que é um programa em execução no computador e que é responsável por executar programas Java. Existem versões diferentes desta Máquina Virtual para diferentes sistemas operativos (Windows, Unix, Linux, Solaris, MacOS, etc). A figura seguinte descreve o processo de criação, compilação e execução de um programa em Java.

Código Fonte Java

Compilador Java

Máquina Virtual Java(JVM, Interpretador Java)

Bytecode Java

Execução

Tradução

O “código-fonte”, quando passa pelo compilador, étransformado num conjunto de bytes formatados – designados de bytecodes.Nesta fase não se trata ainda de “código-máquina”, mas sim de um código intermédio.Os bytescodes não podem ser executados directamente nos diversos processadores. São necessários interpretadores, essa interpretação é feita pela JVM (Java Virtual Machine).

Código Fonte Java

Compilador Java

Máquina Virtual Java(JVM, Interpretador Java)

Bytecode Java

Execução

Tradução

O “código-fonte”, quando passa pelo compilador, étransformado num conjunto de bytes formatados – designados de bytecodes.Nesta fase não se trata ainda de “código-máquina”, mas sim de um código intermédio.Os bytescodes não podem ser executados directamente nos diversos processadores. São necessários interpretadores, essa interpretação é feita pela JVM (Java Virtual Machine).

Figura 6. Processo de criação, compilação e execução de um programa em Java. A utilização do código intermédio tem a vantagem de permitir aos computadores criar programas que podem ser executados em qualquer tipo de computador, sem que tenham que se preocupar com as suas especificações. Desde

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 19

que esse computador tenha a máquina virtual correspondente instalada, qualquer programa Java poderá ser lá executado. Para criar programas em Java é necessário ter instalado no computador, pelo menos o Java Standard Edition Software Development Kit (J2SE SDK) instalado no computador.

1.5.2 - Exemplo de um Programa em Java

De seguida apresentada um programa simples em Java para imprimir uma pequena mensagem no ecrã . public class OlaMundo { public static void main (String[] args){ System.out.println(“Ola Mundo!”); } } Figura 7. Código fonte de um programa em Java.

Ola Mundo! Figura 8. Ecrã com o resultado da execução do programa.

1.6 - Exercícios Práticos

Escreva um algoritmo para resolver cada um dos seguintes problemas. Exerc. 1: Descrever a sequência de passos necessários para pôr um carro a trabalhar. Exerc. 2: Verificar se um número se encontra entre 1 e 10. Exerc. 3: Calcular a nota de uma disciplina que é composta por 20% para o trabalho e 80% para o exame. O utilizador introduz as duas nota e é apresentada a nota final. Exerc. 4: a) Calcular o salário de um funcionário obtendo o valor e o número de horas semanais sabendo que se o número de horas for superior a 40, as 40 horas são pagas pelo preço normal e as restantes pelo dobro do valor. b) Altere o algoritmo anterior de forma a incluir um valor diferente para o número de horas superior a 60. Isto é: Até 40 horas – preço da hora Das 40 às 60 horas – dobro do preço da hora A partir das 60 horas – triplo da hora. Exerc. 5: a) Calcular a média da nota de três exames introduzidos pelo utilizador. b) Altere o algoritmo anterior de forma a receber só notas compreendidas entre 0 e 20 valores. c) Alterar o algoritmo de forma a indicar se o aluno está aprovado (média superior a 10 valores) ou reprovado. Exerc. 6: Dado um valor de temperatura, em graus Celsius, Farenheit ou Kelvin, converter esse valor para as restantes unidades. (Nota: ºC = (ºF-32)*5/9; ºK = ºC+273.15) Exerc. 7: Fazer uma chamada de um telefone público. Deve considerar casos tais como “o telefone está ocupado”, “o telefone está avariado”, “o número desejado está interrompido”, etc. Exerc. 8: Somar um conjunto de 100 números inteiros.

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 20

Exerc. 9: Receber uma seqência de números e determinar se um dado número (também recebido) aparece ou não na sequência. Exerc. 10: Determinar o resultado de uma expressão matemática que utilize os operadores: + e - Exerc. 11: Calcular o perímetro e a área de uma figura geométrica, sabendo que a figura só pode ser um rectângulo ou uma circunferência. Exerc. 12: Procurar uma nota de um aluno numa pauta, através do seu número Exerc. 13: Descobrir um número entre 0 e 1000, pensado por um colega. Após ter acertado informar o colega do número de tentativas efectuadas. Exerc. 14: Determinar se o número é primo. Exerc. 15: Receber uma sequência ordenada de números e determinar se um dados número aparece ou não na sequência. Qual a principal diferenção entre este algoritmo e o exercício 9.

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 21

2 - Introdução as noções de Classe e Objecto

2.1 - Conceito de Objecto e Classe

Antes de introduzirmos os conceitos relacionados com a programação orientada por objectos convém relembrarmos algumas definições que nos acompanham no nosso dia a dia e as quais nos fazem falta daqui para a frente. Ao consultarmos um dicionário constatamos que a definição de conceito é “ Tudo o que o espírito e a alma concebem ou entendem”, mais terra a terra, “ é uma ideia ou noção que aplicamos às coisas, ou objectos da nossa consciência. Por exemplo, para dizermos que temos o conceito de barco apenas precisamos da capacidade de identificar uma instância de um barco. Tendo por base, a definição de conceito e as abstracções que realizamos no nosso dia a dia, é nos possível definir classes. Uma classe não é mais que um grupo de pessoas, animais ou coisas. Mas como os agrupamos? Se pensarmos bem, chegamos à conclusão que ao definir por exemplo um grupo de animais, o fazemos através dos seus atributos, das suas características. Vejamos, no reino animal podemos definir vários grupos, tais como carnívoros vs herbívoros, ovíparos vs mamíferos, entre outras. A linguagem de programação Java diz-se orientada aos objectos. Num paradigma de objectos, ao contrário do que se possa pensar, não se procura uma nova forma de programar, mas sim orientarmo-nos para uma forma de pensar abstracta relativamente a qualquer problema, utilizando para isso conceitos do mundo real. Por exemplo, peguemos num conceito que todos nós conhecemos, o de aluno. Aluno é todo aquele que é educado por um segundo elemento, normalmente numa instituição. Ao conceito de Aluno chamamos de classe, em programação orientada por objectos. Mais, de acordo com a definição de classe mencionada em cima, podemos afirmar que são várias as características de um aluno – nome, número, curso em que está inscrito, turma, entre outras. A estas características chamamos atributos. Atributo define uma característica das futuras instâncias de uma classe. Têm um nome único dentro da mesma classe.

Por outro lado, sabemos ainda que, o aluno pode pagar propinas, pode transitar de ano, pode inscrever-se numa determinada turma, pode mudar de turma. Estes são alguns dos comportamentos que um aluno pode desempenhar,

Nome - João Número - 2134

Curso - EI Turma - A

Ano – 1º

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 22

definindo aquilo que em orientação a objectos designamos de métodos. Os métodos representam funcionalidades específicas da classe. Relembrando o conceito introduzido até aqui, Uma classe é uma descrição de grupos de objectos com propriedades, comportamentos e relações comuns. Define, assim uma categoria de objectos. Analisemos de seguida a seguinte figura:

Temos vários elementos a serem identificados com as mesmas características, nome, número, curso e turma. Aproveitando a classe descrita anteriormente, podemos afirmar que estamos na presença de vários alunos, ou seja, debaixo do mesmo conceito de Aluno. Estamos perante aquilo a que em programação orientada por objectos chamamos de objectos. Visualizamos então vários objectos da classe aluno e verificamos que: Um objecto é um elemento de uma classe e possui as mesmas características e modo de funcionamento que os outros elementos (objectos) da mesma classe. Podemos dizer que o objecto é uma instância de uma classe . Aluno1 é uma instância da classe Aluno. Os objectos colaboram com outros objectos através da troca de mensagens (invocação de métodos) para produzir resultados relevantes para o domínio do problema. Os objectos são normalmente descritos (através das classes) recorrendo a nomes, pronomes, adjectivos ou advérbios. Na figura em cima apresentada temos vários objectos representados:

Classe Aluno Atributos Objecto Nome Número Curso Turma Aluno1 João 2134 EI A Aluno2 Ana 2133 EI A Aluno3 Pedro 2131 EI A Aluno4 Isabel 2135 EI A

Assim, os objectos têm:

João 2134 EI Turma A 1º Ano

Ana 2133 EI Turma A 1º Ano

Isabel 2135 EI Turma A 1º Ano

Pedro 2131 EI Turma A 1º Ano

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 23

• Identidade (definida pela classe) e pelo nome de identificação do objecto; • Estado (atributos) – Cada um conhece e guarda os seus dados, ou seja os valores dos atributos; • Comportamento – métodos, também definidos pela classe. Todos os objectos da mesma classe sabem

executar o mesmo comportamento. É possível dizer neste momento que as classes não são mais do que uma espécie de moldes a partir dos quais criamos instâncias (objectos). Imaginemos que um dos alunos pretende mudar de turma, como faze-lo? Basta recorrer aos métodos existentes na classe, que foram previamente definidos. Vejamos:

O objecto Aluno1 pretende mudar da turma A para a Turma E.

O objecto Aluno1 invoca o método que altera a turma.

Classe Aluno Atributos Objecto Nome Número Curso Ano Turma Aluno1 João 2134 EI 1 E Aluno2 Ana 2133 EI 1 A Aluno3 Pedro 2131 EI 1 A Aluno4 Isabel 2135 EI 1 A

Método define uma funcionalidade das futuras instâncias de uma classe. São normalmente descritos recorrendo a verbos, por indicarem algum tipo de acção. Permitem modificar ou interrogar os objectos relativamente ao seu estado actual. A utilização dos métodos passa normalmente por duas fases:

• Definição - definir o que e que um método sabe fazer no âmbito do objecto a que pertence. • Invocação - processo de enviar mensagens a um objecto para que determinado método do seu

comportamento seja executado. Supondo que uma nova aluna ingressa na escola, será necessário registar um novo aluno. Como? • Criar uma instância da classe Aluno - objecto Aluno5. • Que informação será necessária para criar essa instância? - Nome, número, curso, turma

Classe Aluno Atributos Objecto Nome Número Curso Ano Turma Aluno1 João 2134 EI 1 E Aluno2 Ana 2133 EI 1 A Aluno3 Pedro 2131 EI 1 A Aluno4 Isabel 2135 EI 1 A Aluno5 Rita 2137 EM 1 A

Supondo que desejamos consultar o número de um aluno .

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 24

• Deve-se invocar um método que devolva o número do aluno. Esse método deve ser implementado na classe Aluno.

E que desejamos consultar a turma de um aluno . • Deve-se invocar um método que devolva a turma do aluno. Esse método deve ser implementado na classe

Aluno. No mundo que nos rodeia lidamos com vários grupos de pessoas, animais ou coisas, ou seja, várias classes que coexistem para algum fim. Em programação, podemos criar também várias classes. Imaginemos o seguinte: No domínio Escola que outro conceito podemos encontrar ? O de Professor.

A classe Professor tem os seguintes atributos

• Nome • Numero de Identificação Fiscal • Departamento • Ordenado • Categoria

Relembrando a classe Aluno : A classe Aluno tem os seguintes atributos

• Nome • Numero • Ano • Turma • Curso • Valor da Propina • ValoPago de Propina

Podem verificar que as duas classes possuem atributos com a mesma designação. Isto acontece porque para caracterizar tanto o aluno como o professor precisamos de em ambos definir o atributo nome, por exemplo.

Nome - Pedro Número - 231

Departamento - DSI Categoria - Adjunto

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 25

Nota : Classes diferentes podem ter atributos com o mesmo nome.

2.2 - Exercícios

Grupo I 1. Uma classe e um objecto são a mesma coisa? Se não são, então qual (ou quais) as diferenças e relações

entre estes dois conceitos? 2. No seu ponto de vista o que são atributos, métodos e mensagens?

Grupo II 1. Pretende-se desenvolver uma aplicação para gestão de um empresa de aluguer de automóveis. Deverá ser

possível consultar todos os automóveis existentes na empresa e verficar se um determinado está disponível ou não para aluguer. Quando um automóvel é alugado, o sistema regista este automóvel como ficando indisponível.

a. Quais as classes que a aplicação deve conter? b. Identifique os atributos de cada classe c. Identifique os métodos que cada uma das classes deve ter.

2. Pretende-se desenvolver uma aplicação para desenho. A aplicação permite definir pontos cartesianos e

linhas que se definem dando dois pontos. a. Quais as classes que a aplicação deve conter? b. Identifique os atributos de cada classe c. Identifique os métodos que cada uma das classes deve ter.

3. Pretende-se desenvolver uma aplicação para gestão de uma biblioteca. A aplicação permite consultar os

livros que existem na biblioteca, assim como fazer reserva de livros. Para cada livro, a aplicação guarda a seguinte informação : Autor, titulo, editora. Um utilizador para fazer a reserva de um livro tem que dar os seguintes dados: nome , numero do BI e morada.

a. Quais as classes que a aplicação deve conter? b. Identifique os atributos de cada classe c. Identifique os métodos que cada uma das classes deve ter.

Aluno Nome Numero Ano Turma Curso Valor da Propina ValoPago de Propina

Professor Nome Numero de Identificação Fiscal Departamento Ordenado Categoria

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 26

4. Pretende-se desenvolver uma aplicação para jogar o totoloto. A aplicação deve permitir preencher um boletim realizar o sorteio da chave premiada e realizar a selecção dos boletins premiados.

a. Quais as classes que a aplicação deve conter? b. Identifique os atributos de cada classe c. Identifique os métodos que cada uma das classes deve ter.

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 27

3 - Conceitos básicos de programação em Java

3.1 - Identificadores

Os identificadores são nomes atribuídos aos diferentes elementos de um programa (classes, objectos, métodos, variáveis, constantes e outras entidades que este manipula), os quais em java seguem as seguintes regras: Devem ser iniciados por uma letra, underscore (_) ou cifrão ($) Podem ter outros caracteres (letras, dígitos, underscore ou cifrão) Não podem conter espaços! Contrariamente ao que acontece noutras linguagens, o Java distingue entre maiúsculas e minúsculas, ou seja:

A ≠ a B ≠ b public static void ≠ PUBLIC STATIC VOID

Ainda que as convenções não sejam obrigatórias e o compilador não verifique se são cumpridas, é aconselhável a sua utilização, pois facilitam a compreensão dos programas por programadores a elas habituados. Também para o Java é comum usar convenções para os identificadores a criar quando se desenvolve um programa: • Os nomes das classes começam por letras maiúsculas (ex: Aluno) • Qualquer outro nome começa por letras minúsculas, por exemplo o de um método (ex: main()) • As palavras seguintes à primeira, começam com maiúscula (ex: disciplinaDoCurso) • Os identificadores devem sugerir o seu valor semântico, isto é, devem ter nomes sugestivos de acordo com o

propósito a que se destinam. Exemplo Quais dos seguintes identificadores são válidos em Java e quais não são?

1_x inválido, começa por dígito X1 válido M&M inválido, carácter & é ilegal int inválido, é uma palavra reservada $dólar inválido, carácter acentuado no nome limite Inf inválido, espaço em branco

3.2 - Palavras Reservadas

Os identificadores podem ser escolhidos pelos programadores (ex: numeroDoAluno). No entanto, também se podem utilizar identificadores previamente definidos na linguagem, designados por palavras reservadas. Estas são palavras utilizadas na definição da linguagem e que têm um significado próprio nesse contexto. A sua semântica não pode ser alterada pelo programador.

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 28

Figura 9. Lista das principais palavras reservadas existentes na linguagem Java

3.3 - Símbolos e Valores

Os Símbolos definidos em Java incluem diversos: Operadores: +, -, * e = Sinais de pontuação: {, }, (, ) e ; Tal como as palavras reservadas, os símbolos têm um significado bem definido e não podem ser utilizados para outro fim. Os Valores são dados explícitos que podem ser manipulados pelo programa, isto é são todos os valores aceites pela linguagem. Por exemplo: Número inteiros: 65 e -301 Números reais: 3.14159, -0.02 e 5.88f Os caracteres: ‘a’, ‘A’ e ‘\n’ Cadeias de caracteres: “Bom dia!”

3.4 - Variáveis

Uma variável é uma localização em memória na qual podemos guardar um valor de um dado tipo. A cada variável estão associados um tipo e um nome. O valor de uma variável pode variar durante a execução do programa. No entanto, em cada momento uma variável pode apenas conter um valor. Como podemos verificar na figura seguinte, o armazenamento de um novo valor numa variável destrói o valor anterior dessa mesma variável.

abstract boolean break byte byvalue

case cast catch char class

const continue default do double

else extends false final finally

float for future generic goto

if implements import inner instanceof

int interface long native new

null operator outer package private

protected public rest return short

static super switch synchronized this

Throw throws transient true try

var void volatile while*

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 29

Figura 10. Representação gráfica do conceito de variável

3.4.1 - Variáveis de Instância: Atributos

Como vimos em 3.1 os atributos definem as características das futuras instâncias de uma classe. Têm um nome único dentro da mesma classe. Para referenciar um atributo de um objecto devemos indicar o nome do objecto e o nome do atributo. Classes diferentes podem ter atributos com o mesmo nome. Mais concretamente os atributos são variáveis que guardam os valores que caracterizam os objectos. Mas para cada característica teremos que indicar qual o tipo de dados a que pertence. Ao definir uma classe em Java que represente as características de um aluno teremos os seguintes atributos:

int numero; String nome; int ano; String curso; char turma; double valorPropina; double valorPago;

Para podermos definir atributos em Java precisamos de dominar os seguintes conceitos:

• Como declarar uma variável. • Tipos de dados que uma variável pode ter. • O que significam as palavras reservadas (char, int, double, String).

3.5 - Tipos de Dados

Em Java temos dois grupos de tipos de dados: Tipos de Dados Primitivos: são utilizados para guardar números, caracteres e valores booleanos. Armazenam directamente os valores. Tipos de Dados Referenciados: não guardam os dados directamente, mas são utilizados para guardar os endereços de memória onde se encontram estes dados. Exemplo:

Célula de memória

1002

A Célula de memória

1002

char turma = ‘A’ turma -> endereço de memória 1002

turma = ‘E’ turma -> endereço de memória 1002

E

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 30

int numero = 2133; // a variável numero é do tipo primitivo

String nome = new String (”Pedro”); // a variável nome é uma referencia

Figura 11.

Figura 12.Representação gráfica da possível localização em memória das variáveis declaradas nos dois exemplos anteriores

• A variável número guarda o valor 2133. • A variável nome guarda o valor 40B40. Este valor representa a zona de memória onde está guardada a

cadeia de caracteres “Pedro”. Por isso diz-se que a variável nome é uma referência. Um tipo de dados é definido pela gama de valores que pode representar e pelas operações que sobre eles se podem efectuar.

3.5.1 - Tipos de Dados Primitivos

Por agora vamo-nos focar apenas nos tipos de dados primitivos. A linguagem Java coloca oito tipos de dados primitivos à nossa disposição:

• Quatro representam inteiros: byte, short, int, long • Dois representam números Reais: float, double • Um representa caracteres: char • Um representa valores Lógicos : boolean

memória

“Pedro”

20A20

30A40

40B40

2133numero

nome 40B40

referência

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 31

3.5.1.1 - Inteiros Tipo Inteiro

Tama-nho Menor Valor

Maior Valor

byte 1 byte (8 bits)

−128 127

short 2 bytes (16 bits)

−32,768 32,767

int 4 bytes (32 bits)

−2,147,483,648 2,147,483,647

long 8 bytes (64 bits)

−9,223,372,036,854,775,808 9,223,372,036,854,775,807

Figura 13. Diferentes tipos de inteiros oferecidos pela linguagem Java. Nesta tabela podemos ver o espaço ocupado

por uma Figura 14. variável de cada um destes tipos, bem como o maior e menor valor que essa variável pode ter.

Como exemplos de valores típicos a guardar em variáveis de cada um dos tipos inteiro podem ser apresentados:

byte: 40 short: -22 500 int: 1 500 000 long: 4 000 000 000

3.5.1.2 - Reais Um número real pode ser representado usando a notação decimal, tem um ponto decimal ou a notação exponencial, tem um expoente (E) Ex: 5.0, 12.34, 0.0, -45.8, 12. , 5.6E27

Tipo Tamanho

float 4 bytes (32 bits) double 8 bytes (64 bits)

Figura 15. Tipos de dados reais existentes em Java

Tipo Menor Valor Maior Valor

float 1.40129846432481707e-45 3.40282346638528860e+38 double 4.94065645841246544e-324 1.79769313486231570e+308

Figura 16. Maior e menor valor representáveis pelos diferentes tipos de dados reais do Java

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 32

3.5.1.3 - Caracteres O armazenamento de caracteres em Java é conseguido pelo tipo char. Na realidade, as variáveis do tipo char armazenam números que identificam os caracteres de acordo com um código denominado UNICODE. Este código é um standard internacional de representação de caracteres que contém símbolos e caracteres dos alfabetos ocidentais e orientais. Os valores do tipo char são delimitados por plicas( ' ): Exemplos:

// 'a' 'X' '7' '$' ',' '\n' // são valores do tipo char

char letra = 'a‘;

3.5.1.4 - Lógico O armazenamento de valores lógicos em Java é conseguido pelo tipo boolean, que, evidentemente, apenas pode assumir um de dois valores: verdadeiro, ou falso. As palavras reservadas true e false são os únicos valores válidos para um tipo Lógico Exemplo:

boolean terminado = false;

3.5.1.5 - Declaração, Inicialização e Utilização Quando trabalhamos com uma variável destinguimos 3 etapas:

1. Declaração 2. Inicialização 3. Utilização

Para usar uma variável é necessário fazer a sua declaração previamente, isto é, a especificação do seu nome (identificador) e da gama de valores que pode conter (tipo de dados). A declaração é terminada com um ponto e vírgula (;). Este é o símbolo que se usa em Java para indicar o final de qualquer declaração ou instrução.

Figura 17. Esquema representativo da declaração de variáveis A declaração reserva um espaço em memória necessário para guardar o tipo de valor

char turma

ttiippoo ddee ddaaddoo iiddeennttiiffiiccaaddoorr ddaa vvaarriiáávveell

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 33

A inicialização consiste na atribuição de um valor a uma variável: numero = 2133; turma = ‘A’; Não estamos a falar de um valor qualquer, mas sim do valor inicial da variável, que é guardado no espaço reservado. Podemos, no entanto, declarar e inicializar uma variável na mesma expressão. Exemplo:

int sum = 0; int base = 32, max = 149;

É de notar que a declaração de uma variável apenas provoca a reserva de espaço de memória necessário e a sua identificação pelo nome declarado e não define um valor. É na inicialização que a variável fica com um valor definido, podendo a partir de agora ser utilizada. Quando uma variável é referenciada num programa, é utilizado o valor actual (ver código abaixo).

int numero, resultado; // declaração numero = 213; //inicialização resultado = numero + 100; //utilização do número

// e inicialização do resultado

3.5.2 - Tipos de Dados Referenciados

As classes são novos tipos de dados, no sentido que definam a possível gama de valores e operações que podem ser efectuadas com estes valores. Assim os tipos de dados referenciados são classes (e arrays, que estudamos mais tarde). Para declarar uma variável do tipo referenciado deve se indicar o nome da variável e o nome da classe.

String nome; // a variável nome é uma referencia do tipo String

Definição:A variável do tipo referenciado é chamada referência. Uma referência é uma variável que guarda o endereço do local onde se encontra um objecto de uma dada classe. Para atribuir valor a uma referencia, na maioria dos casos, deve ser executado o comando new seguido de nome da classe utilizada na declaração dessa variável. (este comando será explicado em 3.7.1 - )

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 34

String nome; nome = new String(“Pedro”);

O Java tem um conjunto de classes já elaboradas que permite aceder a um conjunto de funcionalidades e propriedades já definidas. Uma destas classes é a classe String que já foi referida aquando da definição dos atributos nome e curso da classe Aluno. É uma classe bastante utilizada e que serve para manipular cadeias de caracteres. Quando é declarada uma variável do tipo String ( String nome) é reservado um espaço em memória para guardar um endereço da futura cadeia de caracteres. Enquanto essa variével não está inicializada, o valor da variável nome é NULL ( isto é a referência não tem valor) . A inicialização pode ser efectuada pela instrução: nome = “Rita”; Cada instância da classe String é uma cadeia de caracteres. Uma String serve para guardar valores constantes, isto é, uma vez que seja atribuido um valor a uma String este não pode ser alterado. Assim, qualquer operação sobre uma String devolve uma nova String (String modificada) String frase = “Introdução à Programação”; String nome = “Rita”; nome = “Pedro”;

Para além de referenciar os objectos das classes já existentes em Java, pode-se referenciar também os objectos de classes por nós criadas, como veremos mais à frente.

frase

nome

“Introdução à Programação”

“Rita”

“Pedro”

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 35

3.6 - Operadores e Expressões

3.6.1 - Operadores de Atribuição

Por vezes é necessário efectuar uma operação sobre uma variável, e em seguida armazenar-se o valor obtido nessa mesma variável. Os operadores de atribuição Java simplificam essas operações.

A instrução num += conta; é equivalente a num = num + conta;

Figura 18. Diferentes representações para os operadores de atribuição

Ao símbolo = chama-se operador de atribuição. A instrução de atribuição permite armazenar um valor numa variável. A expressão da direita é calculada em primeiro lugar, sendo o resultado armazenado na variável da esquerda. Neste contexto, o sinal = deve ler-se “toma o valor de”. Só pode ser atribuído um valor a uma variável que seja consistente com o tipo de dados declarado para essa variável. A mesma variável, pode estar no lado esquerdo e direito da instrução de atribuição. Considere-se o exemplo:

int conta ; conta = 25; conta 25 sum = conta; sum 25 conta = sum + 15; conta 40 conta = conta + 1; conta 41

3.6.2 - Operadores Aritméticos

Operadores que podem ser utilizados sobre valores de tipo inteiro:

Operador += -= *= /= %=

Exemplo x += y x -= y x *= y x /= y x %= y

Equivalente a x = x + y x = x - y x = x * y x = x / y x = x % y

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 36

Operação Símbolo Exemplo Resultado

Adição + 26 + 10 36

Subtracção - 26 - 1 25

Multiplicação * 26 * 10 260

Divisão / 26 / 10 2

Módulo (resto)

% 26 % 10 6

Figura 19. Conjunto de operações que podem ser efectuadas sobre valores do tipo inteiro

A precedência de operadores determina a ordem de execução das operações. Por exemplo considere-se a instrução: System.out.println(30 + 10 / 2); As interpretações possíveis são:

Figura 20.

Grau de Precedência

Operação

Alto ()

Médio -, + (unários)

*, /, %

Baixo +, -

Figura 21. Interpretações possíveis da ordem dos operadores e tabela com as regras de precedência correctas

. Operadores que podem ser utilizados sobre valores de tipo inteiro:

correcto!

30 102

20+= e 30 10

235+ =

errado!

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 37

Operação Símbolo Exemplo Resultado

Adição + 5.4 + 2.0 7.4

Subtracção - 5.4 - 2.0 3.4

Multiplicação * 5.4 * 2.0 10.8

Divisão / 5.4 / 2.0 2.7

Figura 22. Operações possíveis sobre reais

Grau de Precedência

Operação

Alto ()

Médio -, + (unários)

*, /

Baixo +, -

Figura 23. Precedências dos operadores sobre números reais

Figura 24.

3.6.3 - Operadores Lógicos

As expressões lógicas podem utilizar os seguintes operadores lógicos:

! NOT

&& AND

|| OR

Operam sobre operandos lógicos e produzem resultados lógicos. O NOT é um operador unário (tem apenas um operando), enquanto que o AND e o OR são operadores binários (têm dois operandos)

A b a && b a || b a ! a true true false false

true false true false

true false false false

true true true false

true true false false

false false true true

Figura 25. Figura 26. Tabelas de verdade dos operadores &&, || e !

Figura 27.

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 38

3.6.4 - Operadores Relacionais

Relacionam duas expressões de um mesmo tipo de dados e retornam um valor de tipo boolean:

Operador Designação > Maior que >= Maior ou igual a < Menor que <= Menor ou igual a == Igual a != Diferente de

3.6.5 - Expressões

Uma expressão é uma sequência de operadores e de valores. As expressões podem ser calculadas, obtendo-se um novo valor. Podemos ter: Expressões Aritméticas – envolvem operadores aritméticos 5 * ( 2 + 3 ) + ( 7 – 3 ) / 2 Resultado: 27 As expressões aritméticas são calculadas levando em conta a prioridade dos diferentes operadores envolvidos Expressões Lógicas – têm como resultado um valor lógico e são construídas com operadores relacionais e operadores lógicos Exemplos: Exemplo1: Determine o valor das seguintes expressões, indicando também o tipo do valor obtido

Expressão Resultado 3-4*2+1 -4 int 2*(12%5)-(8-3)/2 2 int 2*12%5-8-3/2 -5 int 2.5+6%4*2.1 6.7 double 2*((20/6)+(3*(2-1.5)))% (2.5+1-1.5) 1.0 double Exemplo 2: Determine o resultado das seguintes expressões ou instruções

Expressão Resultado 3+5/2) >= (1-4%2) true x=3 == 4; x fica false 8-1 != 3 + 4 false ‘a’ < ‘b’ || ‘c’ < ‘a’ true (!a && b)|| (a || !b) true para a=true e b=false

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 39

3.7 - Métodos

Definem funcionalidade das futuras instâncias de uma classe. São normalmente descritos recorrendo a verbos, por indicarem algum tipo de acção e permitem modificar ou interrogar os objectos relativamente ao seu estado actual. Um método tem sempre uma assinatura, a qual é constituída por:

• Tipo de retorno • Nome • Número e tipo de parâmetros

O formato geral de um método é o seguinte:

tipoRetorno nomeMetodo(listaParametros) { declaracoes;

instruções; return (se for o caso);

} Nota: Por convenção, em Java, os nomes de classes começam por letras maiúsculas (ex: NomeClasse), ao passo que os nomes de objectos começam com minúsculas (ex: nomeObjecto). Os nomes dos métodos começam também por minúsculas (ex: nomeMetodo). Os parâmetros são os dados de entrada . O objecto para executar uma determinada operação pode precisar de dados. Essa informação é passada através dos parâmetros. Exemplo:

• O aluno para pagar uma prestação da propina precisa de indicar o valor que vai pagar. • O aluno para mudar de turma precisa de indicar qual a nova turma.

Parâmetros São variáveis que referenciam diferentes tipos de dados dos quais o método necessita para levar a cabo a sua tarefa. Através da instrução return é determinada qual o valor que o método devolve return <expressão>; Nota : Dois métodos têm a mesma assinatura quando o nome, o valor de retorno e a lista de parametros são idênticos em ambos. Não é possível na mesma classe a existência de métodos com a mesma assinatura.

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 40

3.7.1 - Método construtor sem argumentos

Uma das partes mais importantes da programação orientada por objectos é saber utilizar correctamente os construtores de objectos. O construtor é um método especial utilizado apenas na criação e inicialização de objectos de uma determinada classe. O seu único e exclusivo objectivo é inicializar os atributos, ou seja, dar um estado inicial ao objecto. Regras na construção de um construtor:

• É sempre de acesso publico. • Tem o mesmo nome da classe. • Não possui retorno.

Podem existir construtores com parâmetros e construtores sem parâmetros. Neste sub-capítulo apenas nos vamos debruçar sobre os construtores sem parâmetros. Vejamos o seguinte exemplo:

class Relogio { private int hora, segundo, minutos; }

De acordo com as regras de criação de um construtor:

class Relogio { private int hora, segundo, minutos; public Relógio() { hora = 24; minutos = 0; segundo = 0; } }

Quando não se define nenhum construtor na classe que especifica o objecto, a máquina virtual encarrega-se de criar um em tempo de execução, equivalente a:

<nome da classe>() { //……. }

Este construtor inicializa os atributos do objecto com valores default, que correspondem a:

• 0 se o atributo for de tipo numérico (short, byte, int, long, double,float, char) • false se o atributo for de tipo boolean

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 41

• null para referências Nota: null representa uma referência nula, não existente, para um objecto pertencente a uma qualquer classe. Instanciação é o processo de criar instâncias (objectos) de uma determinada classe. É uma operação feita sobre a classe e não sobre os objectos (dado que os objectos já são instâncias não faz sentido criar instâncias a partir deles). Para criar uma instância de uma classe utilizamos o operador new, que quando é executado aloca a memória necessária para guardar o objecto em causa na memória.

new <nome da classe> (<lista de parâmetros actuais>);

Para o exemplo anterior da classe Relogio teriamos: Relogio rel = new Relogio( ); Relogio despertador = new Relogio ( ); Teríamos um objecto denominado rel e outro denominado despertador, caracterizados por três atributos: hora, minuto e segundo, cujos valores respectivamente são, 24, 0 e 0. Poderão estes dois objectos existir ao mesmo tempo ? SIM!!!

3.7.2 - Invocação de métodos e passagem de parâmetros

A invocação de um método deve obedecer à seguinte regra: nome_objecto.nome_método(<lista de Parâmetros>) Vejamos um exemplo:

class Teste { public void metodoOla () {

System.out.println(“ola”); }

}

class Programa {

public static void main(String args[]) { Teste obj = new Teste(); obj.metodoOla();//invocação do método

}

}

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 42

Como foi possível ver o objecto obj invocou um método da sua classe. Será possível um objecto invocar um método de outra classe ? Veja-se o próximo exemplo: public class PrimeiraClasse { public PrimeiraClasse() { System.out.println("Sou o construtor por default da PrimeiraClasse"); } public void metodoPrimeiraClasse() { System.out.println("Sou o metodoPrimeiraClasse"); } } public class SegundaClasse { public SegundaClasse() { System.out.println("Sou o construtor por default da SegundaClasse"); } public void metodoSegundaClasse() { System.out.println("Sou o metodoSegundaClasse"); } } public class Principal { public static void main(String[] args) { SegundaClasse segunda = new SegundaClasse(); segunda.metodoPrimeiraClasse(); segunda.metodoSegundaClasse(); } } Ao analisarmos o código verificamos que a instrução segunda.metodoPrimeiraClasse( ) não está correcta. Porquê? Porque o método metodoPrimeiraClasse() não faz parte da classe SegundaClasse. Importante: Todo o objecto só pode invocar métodos da sua classe, tal como podemos ver no exemplo seguinte:

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 43

Passar parâmetros a um método significa chamar esse método dando-lhe como entrada os dados que ele necessita. Estes dados são chamados parâmetros actuais. Na chamada é efectuada a ligação entre parâmetros formais (definidos no cabeçalho do método) e parâmetros actuais. A lista de parâmetros formais e actuais deve ter correspondência. Cada parâmetro de lista de parâmetros actuais deve corresponder, pelo tipo e pela sua posição na lista, a um parâmetro formal definido no cabeçalho do método. Em Java, a passagem de parâmetros é sempre feita por valor. Consideremos o seguinte código:

class Teste { public void passagem ( int var) {

var = var * 2 ; }

}

class Programa {

public static void main(String args[]) { int variavel = 7; Teste obj = new Teste(); obj.passagem(variavel); System.out.println(variavel);

} } O código apresentado ilusta a invocação de um método por parte de um objecto da classe Teste e a passagem de parâmetros por valor. O parametro formal é var e parametro actual é variável. No quadro seguinte podemos seguir o conteúdo das variáveis definidas no programa anterior :

Variáveis Linha de código

variavel var int variável = 7; 7 --------- Obj.passagem(variavel); 7 7 var = var * 2 ; --------- 14 System.out.println(variável); 7 ---------

No exemplo acima as variáveis que estavam envolvidas na passagem de parâmetros (variável e var) eram variáveis do tipo primitivo int. Na passagem de tipos referenciados, quando se está a lidar com variáveis do tipo referenciado, o comportamento é diferente. Este ponto será explicado detalhadamente no capitulo 4 – Tópicos Avançados de POO.

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 44

Para terminarmos este capítulo, iremos ver o retorno dos métodos. No início do capítulo foi dito que através da instrução return é determinada qual o valor que o método devolve.

tipoRetorno nomeMetodo(listaParametros) { declaracoes;

instruções; return (se for o caso);

} Se o método não devolve valor, a instrução return não é especificada e no cabeçalho do método no lugar do tipoRetorno deve se indicar void. Vejamos o próximo exemplo: class Calculo { public int somaValores() { int valorA = 10, valorB = 2; int resultado = valorA+valorB; return resultado; } }

class Programa {

public static void main(String args[]) { Calculo resultado = new Calculo(); int valorRetornado = resultado.somaValores(); System.out.println(valorRetornado); } } O método somaValores é um método que retorna o valor que foi atribuído à variável resultado. Ao analisarmos o método main podemos ver a seguinte instrução valorRetornado = resultado.somaValores(); Que valor guardará a variável valorRetornado ? 12 Reparem que tipo da variável valorRetornado é igual ao tipo da variável resultado. Isto é muito importante, pois devemos sempre garantir a correspondência dos tipos.

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 45

O seguinte exemplo é idêntico ao anterior, mas com passagem de parâmetros: class Calculo { public int somaValores(int valorA, int valorB) { int resultado = valorA+valorB; return resultado; } } class Programa { public static void main(String args[]) { Calculo resultado = new Calculo(); int valorRetornado = resultado.somaValores(2,5); System.out.println(valorRetornado); int x = 10, y = 5; valorRetornado = resultado.somaValores(x,y); System.out.println(valorRetornado); } }

• Da primeira vez que a variável valorRetornado guarda o valor retornado, qual o seu valor ? 7

• Da segunda vez que a variável valorRetornado guarda o valor retornado, qual o seu valor ? 15

• E qual será o valor de x depois de ser utilizado como parâmetro ? 10.

3.7.3 - Métodos construtores com argumentos

É possível agora avançar para a criação de objectos utilizando construtores com uma lista de parâmetros. No exemplo da classe aluno podemos encontrar um: public Aluno(String nom, int num, String curs, int an, char turm) {…} Seguindo a regra de criação de objectos teremos então: Aluno aluno1 = new Aluno(“Pedro”, 2134,”EI”, 1, ‘A’); // A variável aluno1 é uma referência a um objecto. // A variável, na verdade, serve como apontador para o // endereço de memória que o objecto irá ocupar. Aluno aluno2 = new Aluno(“João”, 2133,”EI”, 1, ‘A’);

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 46

Aluno aluno3 = new Aluno(“Ana”, 2131,”EI”, 1, ‘A’); Aluno aluno5 = new Aluno(“Rita”, 2137,”EM”, 1, ‘A’); Em seguida para consolidar os conhecimentos até aqui adquiridos, será apresentado o código da classe Aluno referente à definição de atributos e definição do construtor: public class Aluno { //ATRIBUTOS private String nome; private int numero; private int ano; private String curso; private char turma; private double valorPropina; private double valorPago; //CONSTRUTORES public Aluno(String nom, int num, String curs, int an, char turm) { nome = nom; numero = num; ano = an; curso =curs; turma = turm; valorPropina = 0; valorPago=0; } } A criação de objectos neste exemplo, será criada numa outra classe, na qual está definido o main: class Programa { public static void main(String args[]) { Aluno aluno2 = new Aluno(“João”, 2133,”EI”, 1, ‘A’); Aluno aluno3 = new Aluno(“Ana”, 2131,”EI”, 1, ‘A’); ... } }

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 47

No método construtor da classe Aluno, encontramos as seguintes instruções: valorPropina=0; valorPago=0; No caso das variáveis valorPropina e ValorPago o valor é fornecido directamente. Contudo o valor atribuído pode resultar do cálculo de uma expressão, tal como: class Programa { public static void main(String args[]) { int ano = 2005; int anoNascimento = 1971 int idade = ano - anoNascimento } }

3.7.4 - Métodos selectores

Os métodos selectores são aqueles que devolvem o valor de um atributo da classe. public int getNumero() { return numero; } O método getNumero( )

• devolve o valor da variável numero • o nome do método é getNumero • o tipo de retorno é do tipo inteiro (Como numero é uma variável do tipo inteiro o tipo de retorno também

é do tipo inteiro) A seguir apresentam-se os restantes métodos selectores do nosso exemplo da classe Aluno

• getNome( ) – devolve o nome do aluno • getCurso ( ) – devolve o curso em que o aluno esta inscrito • getTurma ( )– devolve a turma em que o aluno esta inscrito • get Ano( ) – devolve o ano em que o aluno esta inscrito • getPropina ()- devolve o valor da propina paga • getValorPago( ) – devolve o valor já pago da propina

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 48

public String getNome() { return nome; } public String getCurso() { return curso; } public int getAno() { return ano; } public char getTurma() { return turma; } public double getPropina() { return valorPropina; } public double getValorPago() { return valorPago; } Utilizando um objecto da classe Aluno Aluno aluno2 = new Aluno(“João”, 2133,”EI”, 1, ‘A’); • Como consultar o número deste aluno ? Pode-se utilizar um método selector, reparem:

aluno2.getNumero( ); Estará correcto? Não. Trata-se de um método que devolve um valor, logo devemos recebe-lo de alguma forma.

int numero = aluno2.getNumero( );

3.7.5 - Métodos modificadores

Chamam-se métodos modificadores aqueles que servem para alterar/modificar o valor de um atributo. public void setTurma(char novaTurma) { turma=turm; } O método void setTurma(char novaTurma)

• Modifica o valor do atributo turma, (quando um aluno muda de turma o valor tem que se alterar)

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 49

• nome do método é setTurma • o tipo de retorno é do tipo void –não retorna valor nenhum • Recebe como parâmetro o valor para a nova turma, que é do tipo carácter (char)

public void setCurso(String novoCurso) { curso=novoCurso; } O método void setCurso(String novoCurso)

• Modifica o valor do atributo curso ( quando um aluno muda de curso o valor tem que se alterar) • nome do método é setCurso • o tipo de retorno é do tipo void –não retorna valor nenhum • Recebe como parâmetro o valor para o novo curso, que é do tipo String

Exemplo, utilizando a classe aluno Aluno aluno2 = new Aluno(“João”, 2133,”EI”, 1, ‘A’);

Classe Aluno Atributos Objecto Nome Número Curso Turma Aluno1 João 2134 EI A

aluno2.setCurso(“EA”); Ao invocar o método modificador setCurso os atributos deste objecto ficaram:

Classe Aluno Atributos Objecto Nome Número Curso Turma Aluno1 João 2133 EA A

3.8 - Estrutura de Aplicações em JAVA

3.8.1 - Estrutura do programa principal

Regra geral, seja em Java seja noutras linguagens, uma aplicação informática é constituída por um programa principal onde é iniciada a aplicação e quando é executadaa última linha do programa principal a aplicação termina. Em Java, uma aplicação é constituída por uma ou mais classes. Uma (e só uma) dessas classes contém um método chamado main que é o programa principal. Este utiliza então métodos que podem existir na mesma classe ou noutras. Existem três regras importantes na estruturação de um programa (livro FCA – Fundamentos de Programação em Java2):

• Um programa contém: o Declarações de variáveis; o Um método principal chamado main(); o Um conjunto de métodos definidos pelo programador.

• Os métodos contêm: o Declarações de variáveis; o Instruções;

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 50

o Chamadas a outros métodos (predefinidos ou criados pelo programador). Os detalhes de implementação de um método são irrelevantes, desde que se saiba para que é que ele serve, que parâmetros recebe e que tipo de resultado deve produzir (é como se fosse uma caixa negra!).

3.8.2 - Visibilidade das Variáveis

Visibilidade de uma variável é uma noção associada ao local onde a variável é declarada no programa. Podemos então classificar as variáveis da seguinte forma:

• Variáveis locais • Variáveis globais

Uma variável declarada dentro de um subprograma é chamada de variável local a esse subprograma. Uma variável local é criada sempre que o subprograma é activado e destruída quando este termina a sua execução. Ainda que haja outro subprograma que contenha uma variável declarada com o mesmo nome, estamos a falar de variáveis diferentes, que existem em espaços de memória separados, por períodos de tempo diferentes e visibilidades diferentes, pois existem em subprogramas distintos. Uma variável global é aquela que é declarada no início do programa e subsiste até que o programa termine, sendo visível dentro de qualquer subprograma que o constitui. Para além de serem visíveis dentro de qualquer subprograma que constitui a aplicação, as variáveis globais podem também ser utilizadas por esses subprogramas. Não é no entanto aconselhado o uso abusivo deste tipo de variáveis dadas as limitações que causam na legibilidade do código e a facilidade com que provocam o aparecimento de erros difíceis de detectar. Para além disso não contribuem em nada para a reutilização de código pois tornam o código desenvolvido dependente do contexto de utilização. class VisibilidadeVariaveis { private int valor1; // variável global public static int valor2 = 10; public static void mudaValor2(int v2) { // novoValor é uma variável local ao método int novoValor = v2 + valor2; valor2 = novoValor; } ... public static void main(String args[]) { // Resultado = 43! System.out.println(“Valor2 antes da chamada = ” + valor2); mudaValor2(33); System.out.println(“Valor2 depois da chamada = ” + valor2); } }

3.8.3 - Entrada e Saída de Dados

A interacção da aplicação com o utilizador é efectuada através de entrada e saída de dados. Para pedirmos informação ao utilizador temos que ser capazes de ler do teclado. Para mostrar informação ao utilizador temos que ser capazes de escrever para o ecran.

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 51

class Programa { public static void main(String args[]) { Aluno aluno2 = new Aluno(“João”, 2133,”EI”, 1, ‘A’); Aluno aluno3 = new Aluno(“Ana”, 2131,”EI”, 1, ‘A’); aluno3.setTurma(‘E’); int i= aluno3.getNumero(); char t= aluno3.getTurma(); System.out.println(“Numero” + i); System.out.println(“Turma” + t); } } No exemplo de código apresentado, a variável i e a variável t são do tipo de dados primitivo. Será que é possível escrever a seguinte instrução? System.out.println(aluno3); Sim, mas para essa instrução imprimir informação sobre o objecto aluno3, é necessário definir na classe Aluno o método toString(). public String toString() { String str= "Nome:" + nome + "Numero :" + numero + " curso : " + curso + " ano" + ano; return str; }; Voltando ao nosso exemplo do Aluno, para este exemplo ser interactivo, os dados sobre o aluno (nome, numero etc.) devem ser pedidos ao utilizador. A entrada de dados para o programa é feita através da leitura de dados do teclado. . A escrita de informação para o ecran designa-se por saída de dados. Como já temos visto ao longo dos exemplos anteriores, quando queremos escrever para o ecran utilizamos a instrução em Java

System.out.println( x); // Onde x é a variável que se pretende mostrar no ecran. Nota: x pode ser uma variável de um tipo de dados primitivo, ou se x é de um tipo referenciado, então a classe que instancia tem que ter definido o método toString().

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 52

Voltando ao nosso exemplo da classe Aluno… class Programa { public static void main(String args[]) { Aluno aluno2 = new Aluno(“João”, 2133,”EI”, 1, ‘A’); Aluno aluno3 = new Aluno(“Ana”, 2131,”EI”, 1, ‘A’); aluno3.setTurma(‘E’); int i= aluno3.getNumero(); System.out.println(aluno3); } } A classe Scanner, introduzida com a versão J2SE 5.0, é uma classe que permite converter o texto para tipos primitivos. Para ler de forma confortável texto do canal de entrada padrão, é preciso criar primeiro um Scanner sobre canal System.in que esta associado ao teclado

Scanner sc = new Scanner(System.in);

Para cada um dos tipos primitivos há um método correspondente com a assinatura nextXxx() que retorne um valor desse tipo. Exemplo import java.util.*; class ExScanner { public static void main(String[] args)throws InputMismatchException {

Scanner scanTeclado = new Scanner(System.in); System.out.println ("Introduza um inteiro"); int num = scanTeclado.nextInt(); System.out.println ("Numero introduzido:" + num);

}

Tipo de dados metodo int nextInt() char nextChar() double nextDouble() float nextFloat() String next() Exemplo com a classe Aluno

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 53

class Programa { public static void main(String[] args)throws InputMismatchException {

Scanner scanTeclado = new Scanner(System.in); System.out.println ("Introduza o numero do Aluno "); int num = scanTeclado.nextInt(); System.out.println ("Introduza o nome do Aluno "); int nome = scanTeclado.next (); System.out.println ("Introduza o curso do Aluno "); int curso = scanTeclado.next (); System.out.println ("Introduza o ano de inscrição"); int ano = scanTeclado.nextInt (); System.out.println ("Introduza a turma de inscrição "); char turma = scanTeclado.nextChar (); Aluno aluno = new Aluno(nome, num,curso, ano, turma);

} }

3.8.4 - Definição de Novas Classes

Para além de utilizar as classes pré-definidas pela linguagem, é normal que seja necessário definir novas classes que nos ajudem a resolver os nossos problemas (aliás, é isso que temos vindo a fazer em muitos dos exemplos. A classe Aluno, por exemplo, não faz parte da linguagem). Sumariando os passos que tem sido dados para a construção da classe exemplificativa Aluno. Para se definir uma classe deve obedecer-se à seguinte estrutura:

• Definir atributos (variáveis) de instância • Definir construtores • Definir métodos (métodos selectores, modificadores e outros)

public class <nome da classe> { //definição dos atributos de Instância <tipo1> <atributo1>; <tipo2> <atributo2>, <atributo3>; // definição dos construtores <construtores> ... // definição dos métodos de instância void <método1>(){...} void <método2>(<parâmetros>){...} <tipo> <método3>(){...} <tipo> <método4>(<parâmetros>){...} }

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 54

3.8.5 - Utilização de classes existentes em JAVA.

Como já foi referido anteriormente o Java tem um conjunto de classes já elaboradas que permite aceder a um conjunto de funcionalidades e propriedades já definidas. Estas classes estão guardadas em pastas compactadas. Para podermos utilizar num programa uma dessas classes é necessário importa-las. A instrução em Java é: import <nome_do_pacote.nome_da_classe> Vamos como exemplos analisar as classes String, Math e Random .

3.8.5.1 - Classe String A classe String que já foi utilizada para definir os atributos da classe Aluno, disponibiliza vários métodos para manipular cadeias de caracteres. Dos quais destacamos os seguintes: Método Descrição String() Cria um objecto do tipo String char charAt(int index) Devolve o caracter da posição index da string int compareTo(String anotherString) Compara duas

Strings int indexOf(String str) Determina a localização da primeira ocorrência de uma

cadeia de caracteres dentro de uma cadeia de caracteres

String toUpperCase() Transforma em maiúsculas a cadeia de caracteres int lenght() Retorna o comprimento da string Nota: Para mais informações sobre os métodos disponibilizados pela String consultar a documentação do Java. Exemplo de utilização dos métodos da classe String Codigo resultado String frase = “Hoje é quinta feira”; frase = “Hoje é quinta feira”; int tamanho = frase.lenght(); tamanho=19 String palavra = frase.substring(0,4); palavra=“Hoje ” String novaPalavra = frase.toLowerCase(0,4); novaPalavra=“hoje ” char c = palavra.charAt(2); c=‘j’ boolean b = novaPalavra.equals(“Hoje”); b=false int indice = frase.indexOf(“qui”); indice=7 String outraPalavra = frase.substring(indice,indice+7); outraPalavra=“quinta ” String outra = outraPalavra.trim(); outra=“quinta” A classe String pertence ao package java.lang , este package é importado automaticamente sem necessidade de inclusão específica no programa.

3.8.5.2 - Classe Math Uma classe das classes previamente elaboradas é a classe Math que inclui um vasto número de subprogramas que implementam diversas funções matemáticas (ex: Math.sqrt() – calcula a raíz quadrada; Math.sin() – calcula o seno de um ângulo; etc.)

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 55

A classe Math pertence ao package java.lang , este package é importado automaticamente sem necessidade de inclusão específica no programa. Para utilizar classes de outros pacotes é necessário importar (import) explicitamente a classe. Exemplo: Calcular a potência de um número elevado a outro. public class Calculo { public static void main (String args[]){ int base=2, expoente=8; int resultado; resultado = Math.pow(base, expoente); System.out.println(“O resultado é: ”+resultado); } }

3.8.5.3 - Classe Random A classe Random é parte do package java.util (fornece métodos para gerar números aleatórios). Como não é uma classe do package java.lang é necessário importar explicitamente: import java.util.Random; Quando é necessário utilizar uma classe de um package mas não queremos usar a directiva import, pode ser utilizado o seu nome completo. Alguns métodos da classe Random

Método Descrição Random() Cria gerador de números aleatórios int next(int bits) Gera o número aleatório seguinte int nextInt() Retorna um número inteiro aleatório int nextInt(int n) Retorna um número inteiro aleatório de um intervalo de 0 a n double nextDouble() Retorna um número real aleatório, entre 0.0 e 1.0

public class Calculo { public static void main (String args[]){ int base=2, expoente=8; java.util.Random r = new java.util.Random(); int resultado = r.nextInt(); System.out.println(“O resultado é: ”+resultado); } }

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 56

A desvantagem é que o nome que temos a escrever se torna demasiado extenso, pelo que nem sempre compensa utilizar esta abordagem. A outra abordagem possível, consiste em utilizar de forma explícita a directiva import: import java.util.Random; public class Calculo { public static void main (String args[]){ Random r = new Random(); int resultado = r.nextInt(); System.out.println(“O resultado é: ”+resultado); } }

3.8.6 - Comentários

Os comentários de um programa documentam as instruções existentes. Devem ser incluídos de forma explicar o propósito do programa e descrever passos do processamento. Não influenciam o funcionamento do programa pois são ignorados pelo compilador. Os comentários em Java têm dois formatos: // formato utilizado para comentários no final da linha /* formato para comentários que se estendem por mais de uma linha */

3.8.7 - Paragrafação / Indentação

Caracteres de espaço, linhas em branco e tabulação são genericamente designados por espaços em branco. Os espaços em branco são utilizados para separar identificadores e símbolos no programa. Todos os espaços em branco adicionais são ignorados. Um programa Java pode ser formatado de múltiplas formas. Deve ser utilizada a paragrafação, para assegurar a legibilidade dos programas Exemplo de um programa Java com paragrafação package meuteste; public class OlaMundo { public static void main(String[] args) { System.out.println("Olá Mundo!"); } }

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 57

Exemplo de um programa Java sem paragrafação package meuteste; public class OlaMundo { public static void main(String[] args) { System.out.println("Olá Mundo!"); } } O Compilador ignora a paragrafação e os fins de linha.

3.9 - Exercícios Práticos

Objectivos da Série: Com esta série de problemas pretende-se que o aluno: Conheça as bases da programação orientada pelos objectos Saiba criar novas classes e instanciá-las 1. Relativamente à classe Aluno do exemplo deste capítulo implemente em Java as seguintes alterações

a. Defina dois novos atributos relacionados com as notas de entrada para a escola. Nota da prova especifica de matemática e valor da média do 12º ano.

b. Defina um novo construtor para a classe aluno que também inicialize estes dois novos atributos c. Implemente um método que retorne a media aritmética entre a nota da prova específica e a nota do 12º

ano d. Implemente na classe programa a criação de um novo aluno com os seguintes dados

Objecto Nome Número Curso Turma Especifica

de Mat 12º ano

aluno6 Joana 2155 EM B 13.1 11.2

e. Implemente na classe programa a criação de um novo aluno com dados pedidos ao utilizador. f. Implemente na classe programa a funcionalidade da mudança de turma. Deverá pedir ao utilizador a

nova turma. E no final imprimir os novos dados do aluno, através do uso implícito do método toString. 2. O resultado do exercício do capitulo 2 - grupo2-ex1, deverá ser implementado em Java.

a. Defina a classe com os atributos e métodos identificados. b. Implemente a classe programa onde testa o construtor, os métodos selectores e modificadores.

3. Defina a classe Ponto representada por duas coordenadas.

a. Implemente o método construtor para inicializar o ponto. b. Implemente os métodos para visualizar as coordenadas do Ponto c. Implemente um método que faça uma translação vertical do ponto. d. Implemente um método que faça uma translação horizontal do ponto. e. Implemente um método que calcule o ponto médio linha.

4. O resultado do exercício capitulo 2 - grupo2-ex4, deverá ser implementado em Java.

a. Defina as classes com os atributos e métodos identificados. b. Implemente a classe programa onde testa o construtor, os métodos selectores e modificadores c. Implemente o método que gera os 6 números da chave do totoloto. Devera utilizar a classe Random.

5. Implemente a classe Moeda que tem como atributos o valor monetário da moeda e tipo deMoeda (ex, dólar,

euro, Franco suisso). a. Implemente o método construtor b. Implemente os métodos

i. Verificar se duas moedas são iguais. ii. Adicionar moeda

c. Implemente a classe programa onde testa o construtor e os métodos anteriormente implementados..

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 58

4 - Instruções de Controlo

Até aqui, todos os exemplos de código que vimos seguiam uma estrutura a que se dá o nome de sequencial. Não tinham nenhuma instrução que de alguma forma fizesse mudar o fluxo de execução da aplicação. Ou seja, as instruções são executadas uma após a outra de acordo com a ordem por que aparecem. Esta filosofia limita em muito a utilidade dos programas que se possam vir a produzir. Resolver problemas mais complexos exige um maior poder de decisão sobre a forma como o programa é executado (fluxo de execução), o que nos é possibilitado pelas instruções de controlo. O que estas trazem de novo é a capacidade de controlar a execução de uma aplicação mediante o estabelecimento de condições lógicas. Existem essencialmente dois tipos de instruções de controlo: Selecção: permitem determinar o caminho a seguir de acordo com o valor de uma expressão; Repetição: permitem controlar o número de vezes que um determinado bloco de instruções é executado (são os chamados ciclos).

4.1 - Selecção

Ao implementar aplicações podemos ter que tomar decisões com base em valores de expressões, dados fornecidos pelo utilizador, resultados calculados, etc. Deste tipo de necessidades surgiram as instruções de selecção: para impôr a execução condicional de instruções. A selecção de instruções pode ser: Simples: Com base na condição a avaliar executa um bloco de instruções ou então não executa; Em alternativa: Tem duas possibilidades de blocos de instruções a executar. Com base na condição, ou executa um ou executa outro. Múltipla: As possibilidades são várias e as condições a verificar também, o bloco a executar é escolhido com base na condição cuja verificação tenha sido positiva. Em Java as instruções de selecção são as seguintes: if/else switch - case Com estas instruções podemos concretizar cada um dos três tipos de selecções acima mencionados.

4.1.1 - Selecção Simples: if

Um exemplo de uma selecção simples representado por um fluxograma pode ser o seguinte:

Fluxograma de uma instrução de selecção simples

Instruções... Verdadeiro

Falso

Expressão

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 59

Começa por ser avaliada uma expressão lógica. Se o seu resultado for verdadeiro, então é executado um determinado bloco de instruções. Caso contrário, a execução do programa prossegue sendo esse bloco ignorado. Em Java, este tipo de selecção concretiza-se recorrendo à instrução if, cuja sintaxe é a seguinte:

Figura 28. Instrução de selecção if

Código exemplo para uma instrução if: if (condição) { instruções; } Exemplo 1: public class TesteIdade { public static void main(String args[]) { int idade = 14; // Verificar se um individuo tem // idade para conduzir if (idade < 16) System.out.println(“Muito novo para guiar”); } } Exemplo 2: // Programa que gera um número aleatório e informa se // o número gerado é ou não negativo import java.util.Random; public class NumNeg { public static void main(String args[]) { Random random = new Random(); int n = random.nextInt(); System.out.println(“n = ” + n); if (n < 0) System.out.println(“O número é negativo”); System.out.println(“Adeus.”); } }

if instrução expressão ( )

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 60

Exemplo 3: Relativamente à classe Aluno, do exemplo que temos vindo a acompanhar, implemente um método que retorne falso se o valor da propina é igual a zero. public boolean verificaValorPropina() { if (valorPropina == 0) return false; }

4.1.2 - Selecção Em Alternativa: if-else

Muitas vezes interessa-nos que, quando a condição a verificar seja falsa, haja um conjunto alternativo de instruções a executar. É a isto que se dá o nome de selecção em alternativa, que, em termos de fluxograma pode ser representada da seguinte forma:

Figura 29. Fluxograma de uma instrução com selecção alternativa

Recapitulando: Se a expressão for verdadeira, é executado o conjunto de instruções A. Se for falsa, é executado em alternativa o conjunto de instruções B. O programa segue depois com as instruções que tiver para executar a seguir. Em termos de sintaxe Java, este tipo de selecção representa-se da seguinte forma:

Figura 30. Instrução de selecção if-else

A - Instruções... Verdadeiro Falso B - Instruções... Expressão

if instrução expressão

else

( )

instrução

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 61

Código exemplo de uma instrução if/else: if (condição) { // as chavetas aparecem quando há mais que // uma instrução a executar dentro do if ou // do else. Passa a ser composto! instruções; } else { instruções; } Exemplo 1: public class TesteNota { public static void main(String args[]) { int Nota = 14; // Resultado da avaliação if (nota < 10) System.out.println(“Nota negativa”); else System.out.println(“Nota positiva”); } } Exemplo 2: // Programa que gera dois números aleatórios // e informa qual deles é o menor. import java.util.Random; public class Menor { public static void main(String args[]) { Random random = new Random(); int m = random.nextInt(); System.out.println("m = " + m); int n = random.nextInt(); System.out.println("n = " + n); if (m < n) // o que acontece se m=n? System.out.println(“O menor numero e " + m); else System.out.println("O menor numero e " + n); } } As instruções if podem ser representadas em paralelo ou encadeadas, caso haja várias alternativas a estudar e a representar.

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 62

Exemplo 3: Relativamente à classe Aluno, implemente um método que retorne falso se o valor da propina é igual a zero e verdadeiro se o valor for diferente de zero. public boolean verificaValorPropina() { if (valorPropina == 0) return false; else return true; } Exemplo 4: // Determinar a ordem de grandeza // dos três números (a, b, c) usando if’s encadeados.

// código: if (a < b) if (b < c) System.out.println("a < b < c"); else if (a < c) System.out.println("a < c < b"); else System.out.println("c < a < b"); else if (a < c) System.out.println("b < a < c"); else if (b < c) System.out.println("b < c < a"); else System.out.println("c < b < a");

a < b < c a < c < b c < a < b b < a < c b < c < a c < b < a

sim

não

sim

não

(b < c) ?

(a < c) ?

sim

não

(a < c) ?

(b < c) ?

sim

não (a < b) ?

sim

não

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 63

// Determinar a ordem da grandeza // dos três números (a, b, c) usando if’s paralelos.

// código: if (a < b && b < c) System.out.println("a < b < c"); if (a < c && c < b) System.out.println("a < c < b"); if (b < a && a < c) System.out.println("b < a < c"); if (b < c && c < a) System.out.println("b < c < a"); if (c < a && a < b) System.out.println("c < a < b"); if (c < b && b < a) System.out.println("c < b < a"); Essencialmente, ao tomar a decisão de usar if’s de forma encadeada ou em paralelo estamos apenas a ter em conta o facto de cada condição a verificar depender ou não das anteriores. Em relação ao uso específico da alternativa else, há uma nota importante a fazer. Há casos em que o else pode, em termos semânticos, tornar-se ambíguo, ou seja, ser susceptível de interpretações diferentes numa mesma situação. Exemplo 5: if ( numeroAluno > 1200) if (numeroAluno < 2000) System.out.println("O aluno tem um numero entre 1201 e 1999"); else System.out.println("O aluno tem um numero inferior ou igual a 1200"); A que if pertence o else? Da forma como está escrito o código, parece ser dado a entender que o else representa a alternativa à condição numeroAluno > 1200.... Mas na realidade o código tem um erro de indentação e o else representa uma alternativa à condição numeroAluno < 2000.

a<b? b<c?

a<c? c<b?

b<c? c<a?

b<a? a<c?

c<a? a<b?

c<b? b<a?

a<b<c

a<c<b

b<a<c

b<c<a

c<a<b

c<b<a

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 64

Não podem existir ambiguidades quanto ao caminho a seguir na execução de instruções. Se não tivesse sido estipulada à partida uma regra para o Java operar nestes casos, o interpretador não saberia o que fazer quando lhe surgisse um conjunto de instruções deste género. Em Java, a semântica da instrução if/else dita que um else "pertence" sempre ao if que foi deixado em aberto em último lugar. Ou seja, ao último if sem else. Na situação anterior, para forçar a que o else estivesse associado ao primeiro if, teríamos de usar delimitadores: if ( numeroAluno > 1200) { if (numeroAluno < 2000) System.out.println("O aluno tem um numero entre 1201 e 1999"); } else System.out.println("O aluno tem um numero inferior ou igual a 1200"); Neste caso, dizemos que o segundo if e a mensagem que este envia para o canal de saída (caso a condição seja verdadeira), fazem parte do bloco de instruções a executar quando numeroAluno > 1200 tem o valor true. Tornámo-las numa instrução composta. Nota: Pode haver if’s sem else’s, mas o contrário não se aplica. Exemplo 6: // Se tem menos que 70 pontos, visualizar “Deve melhorar“ // Se tem mais que 95 pontos, visualizar “Trabalho // excelente!“ // Se tem entre 70 e 95, não visualizar mensagem // O código seguinte está certo ou errado? public class Pontos { public static void main(String args[]) { Scanner scanTeclado = new Scanner(System.in); int pontos = scanTeclado.nextInt(); /* Sem as {} sabemos a que if pertence o else? E é esse o resultado desejado? */ if (pontos >= 70) if (pontos > 95) System.out.println(" Trabalho excelente!"); else System.out.println(" Deve melhorar "); } } Aplicando a regra de que um else pertence ao último if deixado em aberto, o else pertence ao if onde se verifica se pontos > 95!

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 65

Em termos sintácticos seria assim que a máquina virtual Java iria interpretar, pois não há margem para ambiguidades. A máquina tem de saber sempre qual é a próxima instrução a executar. Em termos semânticos, claramente teríamos aqui um erro de interpretação do problema e os resultados não seriam os pedidos pelo enunciado.

4.1.3 - Selecção Múltipla: switch - case

Nos tipos de instruções de selecção descritos anteriormente verificámos que é possível utilizar diferentes formas da instrução if para seleccionar a alternativa que mais nos convém. No entanto, se a decisão a tomar tiver que ser feita com base num valor inteiro ou numa letra ao invés de um valor lógico, então a estrutura de selecção múltipla que vamos apresentar torna-se mais eficaz. Em termos de fluxograma pode ser representada da seguinte forma:

Figura 31. Fluxograma de uma instrução de selecção múltipla

Começa por calcular o valor da expressão que tem de ter um resultado de tipo inteiro ou caracter. Depois, compara o valor da expressão com os valores v1 a vn. Se for igual ao de algum deles, executa o bloco de instruções correspondente. Se o valor da expressão a executar não for igual a nenhum dos valores v1... vn, pode suceder uma de duas situações: não há mais nenhuma alternativa a considerar e portanto nenhum bloco de instruções a executar; há uma alternativa pronta a ser executada quando mais nenhuma serve e é essa a escolhida (no fluxograma está representada pelo valor outro). Em Java, a instrução que se usa para representar situações de selecção múltipla é a instrução switch. A instrução switch é também uma instrução de selecção que, com base na avaliação de uma variável ou expressão de valor inteiro (ou caracter) escolhe, entre várias alternativas possíveis, uma instrução ou conjunto de instruções a executar.

I1 I2 In Id

... V1 V2 Vn outro Expressão

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 66

Figura 32. Instrução de selecção múltipla switch-case

A instrução break após cada case serve para evitar que os próximos cases sejam executados. Se há um case que tem o mesmo valor da expressão o seu bloco de instruções deve ser executado e o break faz com que a instrução switch seja terminada. O default é o caso que deve ser executado quando mais nenhum serve (segundo o fluxograma é a opção outro). Os cases que não sejam explicitamente programados num switch sem default são ignorados. A existência do default foca o programador na necessidade de processar condições excepcionais. Há, no entanto, situações em que a utilização do default não é necessária. Nota: Esquecer um break onde ele deve ser usado, conduz a erros lógicos ou semânticos. Embora a ordem dos cases e do default não esteja estipulada à partida, é considerada boa prática colocar o default em último lugar. O break após a última instrução case (ou default, se esta for a última), não é necessário. Muitos programadores colocam-no apenas por uma questão de coerência e simetria para com as anteriores. Exemplo 1: public class Pontos { public static void main(String args[]) { int pontos; Scanner scanTeclado = new Scanner(System.in); System.out.print (“Digite um inteiro entre 1 e 100:> “); pontos = scanTeclado.nextInt(); switch (pontos/10) { case 10: case 9: System.out.println("A - Excelente!"); break; // por exemplo, se o break nao estivesse aqui // e pontos/10 = 9, o bloco seguinte (do case 8) // era executado na mesma, conduzindo a um erro!

switch (expressão)

case

constante

:

instrução break ;

{

} default

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 67

case 8: System.out.println(“B - Bom trabalho!"); break; case 7: System.out.println("C - Pode fazer melhor!"); break; case 6: System.out.println("D - Falamos depois da aula."); break; default: System.out.println("F – Vai trabalhar!"); } } } Exemplo 2: public class TestaCaracter { public static void main(String args[]) { Scanner scanTeclado = new Scanner(System.in); char ch = scanTeclado.nextChar(); switch (ch) { case ‘0’: case ’1’: case ’2’: case ’3’: case ’4’: case ’5’: case ’6’: case ’7’: case ’8’: case ’9’: return (ch – ‘0’); case ‘a’: case ‘b’: case ‘c’: case ‘d’: case ‘e’: case ‘f’: return (ch – ‘a’) + 10; case ‘A’: case ‘B’: case ‘C’: case ‘D’: case ‘E’: case ‘F’: return (ch – ‘A’) + 10; default: System.out.print(“Adeus.”); } } } // Não há breaks porque cada expressão tem um return que // sai do bloco antes que se tente sequer avançar para o próximo! If Versus Switch O if é apropriado para testes em expressões que representem valores lógicos O switch faz selecções com base expressões cujos valores sejam inteiros Utiliza-se o if quando O número de alternativas é pequeno Queremos impor uma ordem na avaliação da expressão A escolha é baseada em gamas de valores (tipo x>1, ou y>100 && y>200... )

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 68

Utiliza-se o switch quando Se testam expressões cujos resultados são valores de tipos enumeráveis (inteiros, caracteres)

4.2 - Repetição

É fundamental que uma linguagem de programação dê suporte à repetição de tarefas, não só por uma questão de eficiência mas também de produtividade. Se há uma tarefa que deve ser executada 500 vezes, não vamos escrever 500 vezes o mesmo bloco de código. Não só deixa de ser produtivo, é cansativo e desmotivante, mas ainda por cima torna o código mais susceptível a erros que para serem corrigidos nos obrigam a percorrer cada um dos blocos de instruções que programámos repetidamente. As instruções que nos permitem resolver este tipo de problemas de uma forma mais eficaz são as instruções de repetição, também conhecidas por ciclos. Um ciclo é uma sequência de instruções executada de forma repetitiva e sujeita a uma condição de término. É normalmente composto por: Corpo: conjunto de instruções a repetir Uma condição ou outra estrutura que controla a execução do corpo, especificando de alguma forma a quantidade de vezes que este deve ser executado (número de iterações). Quando um ciclo não tem fim, ou seja, repete as instruções do corpo indefinidamente, diz-se que se trata de um Ciclo Infinito. Este tipo de situações é absolutamente indesejável pois se um ciclo não termina o programa não avança e, consequentemente, a sua execução também não terá fim nem produzirá resultados. Para além disso, corremos o risco de esgotar os recursos do computador rapidamente se durante esse ciclo interminável houver operações exigentes em termos de requisitos de memória, por exemplo. Em Java ( e na maioria das linguagens de programação de alto nível), há três tipos de instruções de repetição: while do-while for

4.2.1 - Instrução de Repetição while

Esta instrução de repetição baseia-se na avaliação de uma condição lógica para determinar a continuação (ou não) da execução do corpo do ciclo. De acordo com o que nos mostra o fluxograma seguinte, o que vemos é que enquanto a condição tiver o valor verdadeiro (true), o corpo continua a ser executado.

Figura 33. Fluxograma de uma instrução de repetição while

Falso

Expressão Verdadeiro

Instruções

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 69

Figura 34. Instrução de repetição while

Código exemplo de uma instrução while: // as chavetas aparecem se houver mais do que uma instrução // a executar no corpo do ciclo while(condição){ instruções; } Após uma pequena análise dos diagramas e sintaxes apresentados acima, há algumas pequenas notas a fazer: A avaliação da expressão ou condição tem que ter obrigatoriamente como resultado um valor lógico (true ou false). O corpo do ciclo pode ser uma instrução simples ou composta. Isto é, pode haver uma ou mais instruções a repetir. Essas instruções são repetidas enquanto a condição a avaliar em cada passagem for verdadeira. Se a condição a verificar tiver à partida o valor false, o ciclo não chegará a ser executado. Para que o ciclo não se torne infinito, temos de garantir de alguma forma que a expressão avaliada a cada passagem chegará a ter o valor false. Isso consegue-se fazendo com que uma das instruções do corpo do ciclo se encarregue de mudar o valor da condição no momento apropriado. Exemplo 1: public class CicloWhile { public static void main(String args[]) { int a=30, b=15, i=3; while (i>0) { a-=10; b-=5; i--; System.out.println(“A é “ + a + “B é “ + b); } } } // qual é o resultado produzido? Exemplo 2: /* Programa que gera um número entre 1 e 100 é verifica se o número é primo (primo é um número maior que 2 e que é divisível somente por si próprio e por 1) */ import java.util.Random; public class NumeroPrimo { public static void main(String[] args) {

while expressão-lógica instrução ( )

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 70

int d = 2; Random random = new Random(); int x = random.nextInt(100)+1; boolean primo = (x > 1); while (primo && d <= x) primo = (x % d++ != 0); if (primo) System.out.println(x + " e primo."); else System.out.println(x + " não é primo."); } } Exemplo 3: public class CicloInfinito { public static void main(String args[]) { int a=0, i=0; do { ++a; ++i; System.out.println(“A é “ + a); } while (i > 0); } } // Este é um exemplo a não seguir!

4.2.2 - Instrução de Repetição do-while

A instrução de repetição do-while é semelhante à anterior (while), no sentido em que executa o corpo do ciclo enquanto a condição a avaliar for verdadeira. Devem respeitar-se as mesmas regras para evitar a geração de ciclos infinitos, ou seja, há que garantir que no corpo do ciclo existe alguma instrução que no momento certo muda a o valor da condição por forma a quebrar o ciclo. Apesar de o modo de funcionamento ser aparentemente o mesmo, o do-while comporta-se de maneira ligeiramente diferente: primeiro executa o corpo do ciclo e só depois avalia o valor da condição de paragem. Isto faz com que se gere uma nuance que marca toda a diferença: Por avaliar primeiro a condição, um while pode nunca chegar a executar o corpo, se a condição for falsa logo à partida. Diz-se que o while executa 0 ou mais vezes. Por avaliar a condição no fim, um do-while executa sempre o corpo pelo menos uma vez. O do-while executa 1 ou mais vezes.

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 71

Em termos de fluxograma, um do-while pode representar-se da seguinte forma:

Figura 35. Fluxograma da instrução de repetição do-while

Figura 36. Instrução de repetição do-while

Código exemplo para uma instrução do-while: do { // as chavetas aparecem quando o corpo do ciclo tem // mais do que uma instrução a executar! instruções; } while(condição); Exemplo 1: public class CicloDoWhile { public static void main(String args[]) { int a=0, i=0; do { ++a; ++i; System.out.println(“A é “ + a); } while (i<3); } } // qual é o resultado produzido? Exemplo 2: Programa que gera um número entre 1 e 100 e verifica se o número é primo.

do

expressão-lógica

instrução ( ) while

Expressão Verdadeiro

Falso

Instruções

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 72

import java.util.Random; public class Primo { public static void main(String[] args) { boolean primo; int d = 2; Random random = new Random(); int n = random.nextInt(100)+1; do primo = (n % d++ != 0); while (primo && d < n); if (primo) System.out.println(n + " é primo."); else System.out.println(n + " não é primo."); } } Recapitulando: A instrução de repetição while começa por avaliar a expressão : Se for verdadeira entra no ciclo Executa instrução ou bloco de instruções internas ao ciclo A cada nova iteração re-avalia a expressão lógica Se a expressão se tornou falsa o ciclo termina A instrução do-while: Executa o bloco de instruções internas ao ciclo Avalia a expressão Se for verdadeira continua o ciclo, senão termina Conclusão: A instrução do-while executa o bloco de instruções uma ou mais vezes A instrução while executa o bloco de instruções zero ou mais vezes

4.2.3 - Instrução de Repetição for

A instrução for é outra instrução de repetição muito útil, particularmente quando se conhece de antemão a quantidade de iterações necessárias (ou seja, o número de vezes que se pretende repetir o corpo do ciclo). A execução do corpo do ciclo for está, regra geral, dependente da avaliação do valor de uma variável de controlo.

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 73

Figura 37. Instrução de repetição for Código exemplo para a instrução de repetição for: for(expressão1;expressão2;expressão3){ instruções } O modo de funcionamento é o seguinte: Parte de expressão1, é a expressão que inicializa o ciclo atribuindo um valor inicial à variável de controlo. Avalia expressão2 (o teste que é efectuado em cada ciclo). Se é verdadeira: executa instrução executa incremento (instrução que altera o valor da variável de controlo) determinado por expressão3 para a variável de controlo de expressão1 regressa ao passo 2 Se é falsa: Termina o ciclo Em termos de fluxograma, um for poder-se-ia representar da seguinte forma (seguindo literalmente a especificação do ciclo):

Figura 38. Fluxograma da instrução de repetição for

for ( expressão lógica

; expressão

instrução

; expressão )

Instruções

Aplica Experssão 3 a Experssão 1

Verdadeiro

Falso

Expressão

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 74

Notas: Num ciclo for, devemos ter em atenção que, a variável de controlo, ao ser declarada no cabeçalho do ciclo, só é conhecida dentro do seu corpo. Se tentarmos usá-la fora do ciclo obtemos um erro de sintaxe. Para conseguir esse efeito devemos declará-la antes do cabeçalho do ciclo (a inicialização pode, ou não, ser feita nesse cabeçalho). Um erro comum de programação consiste em usar virgulas, ao invés de pontos e virgula, para separar as expressões do cabeçalho do for. Normalmente geram-se erros semânticos/lógicos se colocarmos um ; imediatamente a seguir ao ) do cabeçalho do for, isto porque assim o ciclo não tem corpo e passa a executar uma sucessão de instruções vazias. Exemplo 1: public class CicloFor { public static void main(String args[]) { int a=0, b=0; for (int i=0; i<3; i++) { a+=10; b+=5; System.out.println(“A é “ + a + “B é “ + b); } } } Exemplo 2: // Programa que gera aleatoriamente um número entre 1 e 100 // e verifica se o número é primo. import java.util.Random; public class Primo { public static void main(String[] args) { Random random = new Random(); int n = random.nextInt(100)+1; for (int d = 2; d < n; d++) if (n%d == 0) { System.out.println(n + " não é primo."); return; } System.out.println(n + " é primo."); } }

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 75

Todas as 3 expressões do cabeçalho do for são opcionais: Se omitirmos a expressão2, o Java assume que a condição de continuação do ciclo é true, gerando portanto um ciclo infinito. Podemos omitir a expressão1 se inicializarmos a variável de controlo antes do ciclo. Podemos omitir a expressão3 se o programa calcular o incremento ou decremento com instruções dentro do corpo do ciclo. Ciclos Encadeados Tal como podemos ter instruções de selecção encadeadas, também podemos ter ciclos encadeados, ou seja, ter ciclos dentro de ciclos. A regra dita apenas que o ciclo mais interior é o último a ser executado. Desde que o exterior reúna as condições para prosseguir, o interior também terá a sua chance de realizar trabalho. Exemplo 3: public class CiclosEncadeados { public static void main(String[] args) { final int SIZE = 5; for (int x = 1; x <= SIZE; x++) { for (int y = 1; y <= SIZE; y++) { int z = x*y; if (z < 10) System.out.print(" "); System.out.print(" " + z); } System.out.println(); } } } Nota: Não é aconselhável encadear muitos ciclos uns nos outros. Torna muito mais difícil a manutenção do código e a resolução de problemas, ou seja, aumentamos toda a complexidade da solução. Uma métrica razoável seria nunca utilizar mais do que três ciclos encadeados. while versus do-while, versus for Após sabermos como funciona cada tipo de instrução de repetição reside ainda uma questão por resolver: qual delas deve ser usada em cada situação? Um ciclo for, usa-se essencialmente quando o número de repetições é conhecido antes do início da sua execução. Em Java, o for é flexível o suficiente para que possa ser utilizado em situações onde o número de repetições seja também controlado por uma condição lógica e em que o número de repetições não seja conhecido de antemão. No entanto, apesar de tal ser possível e de produzir um código mais compacto, por norma também é mais difícil de ler e compreender caso tenhamos de corrigir erros. Quando o número de repetições não é conhecido à partida, estando a execução do bloco de instruções dependente apenas de uma condição lógica, devemos então utilizar o while.

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 76

Devemos usar um ciclo do-while em situações em que o bloco de instruções a repetir, para além de estar dependente da avaliação de uma condição lógica, deva ser executado pelo menos uma vez. Aliás, é esse o ponto que marca a diferença entre um do-while e os outros dois tipos de instruções de repetição.

4.3 - Exercícios Práticos

Grupo I 1. Que tipos de instruções de controlo conhece? 2. Na sua opinião, para que servem as instruções de controlo? 3. Qual é o objectivo da instrução if? E do switch? Quais as diferenças entre estas duas instruções de selecção?

Em que tipo de situações se deve usar uma ou a outra? Justifique todos os passos da resposta. 4. Ao utilizar o if tem de utilizar sempre e obrigatoriamente um else? Se não for o caso indique a que situações se

aplicam a utilização do else. 5. É possível ter instruções if encadeadas ou paralelas. Verdadeiro ou falso? 6. Para que serve a utilização da instrução break no código de um switch? 7. O que representa a opção de default? 8. O que é um ciclo? Qual é a motivação que encontra na utilização de instruções de repetição? 9. Quais são as instruções de repetição que conhece? Quais as diferenças entre elas? Quando acha que deve

utilizar cada uma? Justifique cada passo da resposta. 10. É possível codificar ciclos encadeados? Quais são as limitações que encontra neste tipo de solução? 11. O que são ciclos infinitos? Grupo II Exerc. 1: Para os exercícios seguintes indique o output que espera como resultado, tendo em conta a declaração e inicialização das seguintes variáveis: final int MAX = 25, LIMIT = 100; int num1 = 12, num2 = 25, num3 = 87; Alínea A

if (num3 >= LIMIT) System.out.println ("maçã"); System.out.println ("laranja");

System.out.println ("pera"); Alínea B

if (num2 == MAX) {

System.out.println ("maçã"); System.out.println ("laranja");

} System.out.println ("pera");

Alínea C if (LIMIT+num3 <= 150) {

System.out.println ("maçã"); System.out.println ("laranja");

} else

System.out.println ("pera");

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 77

Alínea D if (num1 < MAX)

if (LIMIT >= num2) System.out.println ("maçã"); System.out.println ("laranja");

Alínea E if (LIMIT%num1 + 4 == num1 + (MAX-num2)) {

System.out.println ("maçã"); System.out.println ("laranja");

} else {

System.out.println ("pera"); System.out.println ("banana");

} Alínea F

if (num2 > 18) if (num1 < 0) System.out.println ("maçã"); else System.out.println ("laranja"); System.out.println ("pera");

Alínea G

if (num3 >= MAX) {

if (MAX/num2 == 1) System.out.println ("maçã"); System.out.println ("laranja"); if (LIMIT-num3 > num1+2) System.out.println ("pera"); else { System.out.println ("banana"); System.out.println ("kiwi"); }

} else if (num2*2 == MAX*2) System.out.println ("uva");

Alínea H if (LIMIT >= 4*num2)

if (MAX == 25) System.out.println ("maçã"); else System.out.println ("laranja"); else System.out.println ("pera");.

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 78

Exerc. 2: Para os exercícios seguintes escreva segmentos de código que sirvam para executar as acções indicadas: Alínea A Imprimir “Hurra!” se a variável sum for divisível por count Alínea B Imprimir “Num é zero”, “Num é positivo”, “Num é negativo”, consoante o valor de num. Alínea C Atribuir o valor mais pequeno de dois inteiros à variável smallest utilizando: If-else Operador condicional Alínea D Imprimir “Igual” se dois valores do tipo float guardados em val1 e val2 forem exactamente iguais e “Essencialmente igual” se esses dois valores estiverem a uma distância inferior ou igual a 0.0001 um do outro. Imprimir “Diferente” se não forem de todo iguais ou semelhantes.: Exerc. 3: Nos seguintes exercícios indicar o output que irá ser produzido tendo em conta o valor de base das seguintes variáveis:

final int MIN = 10, MAX = 20; int num = 15;

Alínea A while (num < MAX) { System.out.println (num); num = num + 1; }

Alínea B do { num = num + 1; System.out.println (num); } while (num <= MAX);

Alínea C for (int count1=1; count1 <= 5; count1++) { for (int count2=1; count2 <= 5; count2++) System.out.print (count1*count2 + " "); System.out.println(); }

Alínea D while (num > MIN) { System.out.println (num); num = num - 1; }

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 79

Alínea E while (num < MAX) { if (num%2 == 0) System.out.println (num); num++; }

Alínea F for (int value=7; value < 0; value--) System.out.println (value); Alínea G do { num = num + 1; if (num*2 > MAX+num) System.out.println (num); } while (num <= MAX);

Alínea H for (int value=num; value <= MAX; value++) if (value%4 != 0) System.out.println(value);

Grupo III Exerc. 1: Implemente um método que receba um número e indique se o número é par ou ímpar. Exerc. 2: Implemente um método que receba um caracter e determinar se este corresponde a um dígito. Exerc. 3: Implemente um método que receba um determinado número e informe o utilizador se o mesmo é divisível por 5. Exerc. 4: Implemente um método que receba um número inteiro e verifique se é divisível por 2, 3, 5, 6, 10, 15 ou 30. Exerc. 5: Implemente um método chamado, calcIRS, que receba o ordenado de um trabalhador e devolva o imposto a pagar de acordo com a tabela 2:

Ordenado Taxa <100.000 5% >= 100 000 e < 300 000 15% > 300 000 25%

Tabela 1 Exerc. 6: Observe o código da figura seguinte e indique, caso existam, os erros existentes:

switch(n) { case 1: a=11; b=22; break; case 2: c=33; break; d=44; }

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 80

Exerc. 7: Crie uma classe, chamada Utilitaria, constituída pelos seguintes métodos: a) gerar um número aleatório; b) receber dois números obtidos aleatoriamente e retornar o resultado da operação matemática entre ambos, dependendo do operador escolhido (+, -, *,/) Crie outra classe, chamada Principal, que permita testar os métodos desenvolvidos na classe Utilitaria. Exerc. 8: Implemente um método que receba três valores reais, que correspondem a três lados de um triângulo e que classifique o triângulo como equilátero, isósceles ou escaleno. Exerc. 9: Crie uma classe, chamada Utilitaria, constituída pelos seguintes métodos: a) ler um número inteiro; b) Calcular a soma de um conjunto de números. A quantidade de números é desconhecida à partida. A sequência de entrada só termina quando for introduzido um número negativo. Crie outra classe, chamada Principal, que permita testar os métodos desenvolvidos na classe Utilitaria. Exerc. 10: Implemente um método que recebe um valor n e calcule a soma de n primeiros números positivos. Exerc. 11: Escreva, utilizando um ciclo “for”, um conjunto de instruções equivalente a: while (i<100) System.out.println(i,“ao quadrado é igual a ”,Math.sqr(i)); Exerc. 12: Observe o código da figura seguinte e indique, caso existam, os erros existentes: public class Exercicio { public static void main(String [ ] args){ System.out.print(0); int fib0 = 0; int fib1 = 1; int fib2 = 1; while (fib2<1000); { fib0=fib1; fib1=fib2; fib2=fib0 + fib1; System.out.print(“ , “ + fib1); } } Exerc. 13: Um banco venda moeda estrangeira (Dólares, Francos, Libras, etc.) e leva uma comissão de 2% do valor transaccionado mais 1 Euro. Escreva um programa para indicar qual o valor a pagar por uma certa venda de moeda. O programa recebe a quantia e tipo de moeda a adquirir. As taxas de câmbio existem no programa como constantes. Exerc. 14: Uma certa empresa fabrica motores com potências compreendidas entre 1 e 99cv. Ao processar informação sobre um destes motores, um programa usa um de três procedimentos, de acordo com a potência do motor. Partindo do princípio que o programa está escrito em Java e de que a variável inteira Pot representa a potência do motor a ser fabricado, escreva uma instrução if que execute o procedimento correspondente de acordo com a tabela seguinte:

Potência do motor Acção a executar Pot < 1 Mensagem de erro 1 <= Pot < 5 PW1 5 <= Pot < 20 PW2 20<= Pot < 100 PW3 Pot >= 100 Mensagem de erro

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 81

As condições das instruções if não devem ter conjunções. Exerc. 15: Escreva um programa em Java que converta notas quantitativas de 0 a 20 em notas qualitativas de mau a excelente, utilizando uma estrutura de if’s encadeados e que verifique o limite superior das gamas de cada uma das notas qualitativas. Considere que: 0-4 : Mau 5-9 : Medíocre 10-13 : Suficiente 14-17 : Bom 18-20 : Muito Bom Exerc. 16: Escreva um programa em Java para calcular os juros e o novo saldo de uma conta bancária, tendo em atenção que se o saldo for inferior a 1.000 a conta não recebe juros e paga uma taxa ao banco (multa). Caso a conta atinja um saldo negativo é cancelada. O programa deverá ter a multa representada por uma constante. Deverá ler o saldo anterior, o número de meses ao fim do qual queremos calcular o saldo, e a taxa de juros anual. Parta do princípio de que não há movimentos na conta e de que os juros só são calculados no fim do número de meses especificado. Exerc. 17: Relativamente à classe Aluno, criada no capítulo 3, implemente os seguintes métodos: retornar falso se a nota da prova específica de matemática foi inferior a 12 valores; verificar se a nota da prova específica foi inferior a 12 valores (invoque o método que calcula a média e o implementado na alínea anterior). imprimir um menu que permita ter as seguintes opções: inserir; listar; apagar e procurar aluno e sair do programa. tratar as opções do menu anterior.

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 82

5 - Tópicos Avançados de Classes

Como referido no livro “Fundamentos de Programação em Java2, FCA”, numa linguagem orientada a objectos os programas funcionam através da criação de objectos, dos comportamentos que estes são capazes de apresentar e da comunicação entre eles. Um objecto pode solicitar a outro um determinado comportamento, de entre os que estão definidos. Antes de criar um objecto é necessário ter um “molde” que defina os seus atributos e comportamentos, o qual se denomina por classe. Antes de se criar um objecto é necessário criar a respectiva classe. Podem ser criados diversos objectos a partir de uma classe, cada um com atributos próprios mas com os mesmos comportamentos. As linguagens de programação orientadas a objecto incluem diversas classes predefinidas a partir das quais se podem criar objectos. Contudo, para a maioria dos programas é necessário definir novas classes de forma a poder criar objectos que satisfaçam as necessidades dos programadores. No JAVA, a definição de classes segue a seguinte sintaxe:

public class nomeDaClasse { //Declarações de atributos // Construtores // Métodos }

As variáveis ou atributos, os construtores e os métodos de uma classe são genericamente denominados membros da classe.

5.1 - Variáveis de Instância e variáveis de Classe

Numa classe podem ser declaradas variáveis de dois tipos: variáveis de instância e/ou variáveis de classe. As variáveis de instância são as variáveis definidas para armazenar os atributos específicos de cada objecto, por exemplo a cor, o peso, etc. Cada objecto da classe definida tem a cor e o peso como atributo embora os seus valores possam ser diferentes para cada objecto. As variáveis de classe não existem nos objectos. A declaração de uma variável de classe provoca a criação de uma variável em memória, a qual será partilhada por todos os objectos que forem criados a partir da classe. Assim, as alterações efectuadas por um objecto ao valor de uma variável de classe manifestam-se quando a mesma variável é acedida por qualquer objecto da mesma classe. Este tipo de variáveis utiliza-se quando é necessário partilhar informação entre objectos de uma classe ou aglutinar informação produzida pelos mesmos. Como exemplo de uma variável de classe, podemos considerar uma situação em que se tenha interesse em saber quantos alunos existem. A solução passa pela criação de uma variável de classe da classe Aluno que seja incrementada quando for criado um novo objecto:

public static int numeroDeAlunos = 0;

A palavra reservada static indica ao compilador que deve criar uma variável que é partilhada por todos os objectos da classe e como tal não deve criar uma cópia da variável sempre que for criado um novo objecto.

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 83

Da mesma forma que existem variáveis estáticas também existem métodos estáticos. Os métodos estáticos podem ser invocados sobre a classe, não é necessário criar nenhuma instância da classe (i.e. um objecto) em que foram declarados para os podermos utilizar (um bom exemplo disto são os métodos definidos na classe Math). Os métodos estáticos apenas podem manipular variáveis locais ou então atributos estáticos pois as variáveis de instância só são criadas quando são criadas instâncias da classe. A figura seguinte apresenta um exemplo de utilização de atributos e métodos estáticos. // Demonstração de utilização de atributos e métodos estáticos // Utilizando uma versão simplificada da classe Aluno // versão simplificada da classe Aluno public class Aluno { // VARIÁVEIS DE CLASSE static private int numeroDeAlunos = 0; // VARIÁVEIS DE INSTÂNCIA private String nome; private int numero; //CONSTRUTORES public Aluno( String nom) { nome = nom; numero = this.numeroDeAlunos++ +1; } // método estático – pode ser invocado sem ser criado // nenhum objecto public static int getNumeroDeAlunos() { return numeroDeAlunos; } // selectores public int getNumero() { return numero; } public String getNome() { return nome; } } // Exemplo de utilização de atributos e métodos estáticos public class ExemploVariaveis { public static void main(String[] args) { // Declaração de 3 variáveis do tipo aluno Aluno aluno1, aluno2, aluno3;

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 84

System.out.println(); System.out.print("Número de Alunos existentes :"); //Chamada do método estático da classe Aluno System.out.println( Aluno.getNumeroDeAlunos()); // criar 1º aluno com o nome "António" aluno1 = new Aluno("António"); //Imprimir o número de alunos criados //utilizando um método da classe System.out.print("Número de Alunos (via classe): " + Aluno.getNumeroDeAlunos()); //Imprimir o número de alunos criados utilizando o objecto aluno1 System.out.print("Número de Alunos (via aluno1): " + aluno1.getNumeroDeAlunos()); // criar 2º aluno com o nome "Maria" aluno1 = new Aluno("Maria"); // Obter o nome e número do 1º aluno criado System.out.println("Nome: " + aluno1.getNome()); System.out.println("Número: " + aluno1.getNumero()); // Obter o nome e número do 2º aluno criado System.out.println("Nome: " + aluno1.getNome()); System.out.println("Número: " + aluno1.getNumero()); //Imprimir o valor da variável de classe //que representa o nº de alunos //Imprimir o número de alunos criados //utilizando um método da classe System.out.print("Número de Alunos (via classe): "); System.out.println(Aluno.getNumeroDeAlunos()); //Imprimir o número de alunos criados utilizando o objecto aluno1 System.out.print("Número de Alunos (via aluno1): "); System.out.println(aluno1.getNumeroDeAlunos()); //Imprimir o número de alunos criados utilizando o objecto aluno2 System.out.print("Número de Alunos (via aluno2): "); System.out.println(aluno2.getNumeroDeAlunos()); } }

Figura 39. Demonstração de utilização de atributos e métodos estáticos utilizando uma versão simplificada da classe Aluno

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 85

5.2 - Modificadores de visibilidade

Na linguagem Java existem três modificadores de visibilidade que permitem controlar as permissões de acesso a um membro da classe: public, private e protected. O modificador de visibilidade protected tem a ver com o conceito de herança o qual não é abordado no âmbito desta disciplina. Quando um membro de uma classe é declarado com o modificador public, ele é público e pode ser acedido a partir de qualquer ponto do programa, mesmo por objectos de outras classes. Os membros declarados como private são privados e como tal só são visíveis e dentro da classe onde estão declarados, pelo que não podem ser directamente utilizados a partir de outros objectos. Como regra geral, as variáveis de instância dos objectos devem ser declaradas com visibilidade private. Os métodos que implementam os serviços fornecidos pelo objecto devem ser declarados public para que possam ser chamados a partir de outros objectos. Denomina-se por interface do objecto o conjunto de serviços (o conjunto de métodos) disponibilizados pelo objecto. Os métodos que não pertencem à interface são métodos utilizados para auxiliar a implementação dos serviços e devem ser declarados como privados.

5.3 - Encapsulamento

O conceito de encapsulamento representa o princípio que cada objecto deve ser responsável pelos seus próprios dados e deve controlar o seu funcionamento. Um objecto deve funcionar como uma caixa negra que é capaz de apresentar um conjunto de comportamentos se for solicitado. Para o exterior basta dar a conhecer os comportamentos possíveis e os seus efeitos, mas não a forma como são implementados Um objecto pode ser considerado sob duas perspectivas: a interna e a externa. A perspectiva interna tem a ver com a estrutura dos seus dados e com os algoritmos utilizados para implementar os seus comportamentos. Esta perspectiva apenas interessa ao programador que criou a classe, pois só este necessita de conhecer os seus detalhes internos. Numa perspectiva externa, um objecto é visto como uma entidade encapsulada, que apenas responde a um determinado conjunto de pedidos que lhe podem ser feitos por outros objectos. Estes pedidos correspondem ao conjunto de comportamentos definidos como públicos na classe do objecto, i.e., acessíveis do exterior. Esta perspectiva permite a reutilização do código do objecto uma vez que os detalhes internos de um objecto são independentes do contexto da sua utilização. Para obter este nível de independência, um objecto deve ser auto-contido, ou seja, qualquer alteração do seu estado (das suas variáveis) deve ser provocada apenas pelos seus métodos e não deve permitir que outro objecto altere o seu estado.

5.4 - O Operador de Auto-Referenciação this

A palavra reservada this pode ser utilizada, dentro de um bloco de um método, para referir o objecto actual. this é um “apontador” ou uma referência para o objecto em questão. Usando este apontador, um método pode aceder a todas os atributos da classe a que pertence. this é criado automaticamente quando um objecto chama um método e “aponta” para o próprio objecto que chamou o método. // exemplo de utilização de this com a classe Aluno … //ATRIBUTOS private String nome; private int numero; private int ano; private String curso; private char turma;

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 86

private double valorPropina; private double valorPago; //CONSTRUTORES public Aluno(String nome, int numero, String curso, int ano, char turma) { this.nome = nome; this.numero =numero; this.ano=ano; this.curso=curso; this.turma=turma; valorPropina=0; valorPago=0; }

Figura 40. Exemplo de utilização de this com a classe aluno Neste caso o operador this ajuda ainda a resolver ambiguidades. Caso contrário como saberíamos de que nome, numero, ano, curso ou turma se estava a falar? Quando se utiliza this.nome estamos a referenciar a variável de instância nome pertencente ao objecto que está a ser criado, evitando deste modo a confusão com o parâmetro nome do método construtor Aluno.

5.5 - Passagem por Parâmetros Referenciados

Como foi referido anteriormente, em Java, a passagem de parâmetros é sempre feita por valor. Contudo, quando se passa um objecto como parâmetro, na realidade o que é passado é o valor da referência do objecto e não o objecto propriamente dito. Deste modo, as alterações efectuadas sobre um objecto recebido como parâmetro de um método reflectem-se fora do mesmo. Todos os tipos de dados em Java que não sejam primitivos são objectos. As variáveis que representam objectos são na realidade referências (apontadores) para zonas de memória onde estes estão armazenados. Ao passar como parâmetro para um subprograma uma variável que representa um destes tipos, estamos a passar uma cópia da referência para o mesmo. Isto significa que, se dentro do subprograma fizermos alguma operação sobre essa variável, estamos na realidade a alterar o objecto e quem chamou o subprograma vê essa alteração. Isto provoca um comportamento idêntico ao da passagem por referência. // exemplo de passagem por parâmetros referenciados public class Referencia { public static void main(String[] args) { Aluno aluno = new Aluno("João", 2133,"EI", 1, 'A'); // escreve o nome do aluno – "João" System.out.println( aluno.getNome()); // passagem “por referencia” de aluno mudaNomeAluno(aluno); // escreve o nome do aluno após alteração no subprograma – "José" System.out.println( aluno.getNome());

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 87

} public static void mudaNomeAluno( Aluno aluno1) { aluno1.setNome("José"); } }

Figura 41. Exemplo de passagem por parâmetros referenciados

5.6 - Sobrecarga de Métodos

O Java permite a sobrecarga de métodos. Diz-se que existe sobrecarga de métodos sempre que numa classe existem vários métodos com o mesmo nome, mas diferentes assinaturas. Por exemplo, na classe String existem diversos métodos valueOf, por exemplo: static String valueOf(boolean b) static String valueOf(char c) static String valueOf(char[] data) static String valueOf(boolean b) A sobrecarga de métodos é bastante utilizada no caso dos construtores. Como exemplo podemos ver a figura seguinte onde são definidos dois construtores para aluno, os quais podem ser utilizados conforme a informação disponível na altura da criação do objecto da classe Aluno. public Aluno(String nome, int numero, String curso) { this.nome = nome; this.numero =numero; this.ano=1; this.curso=curso; this.turma=' '; valorPropina=1000; valorPago=0; } public Aluno(String nome, int numero, String curso, int ano, char turma) { this.nome = nome; this.numero =numero; this.ano=ano; this.curso=curso; this.turma=turma; valorPropina=1000; valorPago=0; }

Figura 42. Exemplo de sobrecarga do construtor

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 88

5.7 - Exercícios Práticos

Objectivos da Série: Com esta série de problemas pretende-se que o aluno:

• Saiba diferenciar e utilizar variáveis de instância e variáveis de classe; • Compreenda os modificadores de visibilidade apresentados e as situações em que cada um deve ser

utilizado • Utilize o operador de Auto-referenciação this

Parte I – Questões Teóricas

1. Diga o que entende por variável de classe e variável de instância. Mencione as diferenças entre ambas e justifique a resposta.

2. Como pode criar e utilizar variáveis de classe? Isto é, quais são os passos a dar? Justifique e dê exemplos. 3. Para utilizar uma variável e/ou um método estático de uma classe necessita de instanciar a classe?

Justifique. 4. Métodos estáticos podem referenciar atributos que não sejam estáticos? Justifique. 5. O que é e para que serve o operador this?

Parte II – Aplicação de Conceitos Usando Pequenos Programas Exerc. 1: Indique qual o resultado visualizado no ecrã após a execução do seguinte programa: public class VariavelDeClasse { static int n = 2; String descricao; public static void main(String[] args) { VariavelDeClasse v1 = new VariavelDeClasse(); v1.n = 1; VariavelDeClasse.n--; v1.descricao = "Ola"; VariavelDeClasse v2 = new VariavelDeClasse(); v2.n = 2; VariavelDeClasse.n++; v2.descricao = "isto e um teste"; System.out.print(v1.descricao + " "); System.out.print(v1.n); System.out.print(" ** "); System.out.print(v2.descricao + " "); System.out.print(v2.n); } } a) Ola 1 ** isto e um teste 2 b) Ola 2 ** isto e um teste 3 c) Ola 3 ** isto e um teste 3 d) Ola 0 ** isto e um teste 3 Exerc. 2: No exercício anterior, indique onde se encontra uma variável de classe e uma variável de instância.

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 89

Exerc. 3: Crie um programa que determine a partir das coordenadas de 3 pontos, fornecidas pelo utilizador, o tipo de triângulo que estas representam (equilátero, isósceles ou escaleno). Deve também mostrar se se trata ou não de um triângulo rectângulo. Nota:

1. Triângulo equilátero tem os 3 lados iguais. 2. Triângulo isóscele tem 2 lados iguais. 3. Triângulo escaleno tem os 3 lados diferentes. 4. Um triângulo é rectângulo quando verifica a propriedade dada pelo teorema de Pitágoras: o quadrado da

hipotenusa é igual à soma dos quadrados dos catetos. Deve implementar:

1. A classe ponto para representar as coordenadas e 2. A classe triângulo para representar triângulos. 3. Em separado terá a classe que contém o programa principal e faz uso das outras duas para cumprir os

objectivos pretendidos.

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 90

Valor 1

Saída

Programa

Variável 1

Variável 2

Variável 3

Valor 2

Valor 3

Valor 1

Valor 2

Valor 3 Saída

Valor 4

Valor n

...

Programa

variavel

6 - Tabelas

6.1 - Motivação

Um programa que manipule vários valores, armazena estes valores em algumas variávei, faz o respectivo processamento e envia o resultado para o exterior (fig.-1).

Figura 43. Armazenamento, processamento de valores e saída. Nem sempre os programas manipulam tão poucos valores, podendo necessitar de manipular vários valores. Estes podem ser lidos e processados um de cada vez(fig.-2).

Figura 44. Manipulação de vários valores Imaginemos agora um programa que irá ler vários valores e imprimi-los pela ordem inversa. O programa deve processá-los “quase todos ao mesmo tempo” para produzir a saída desejada (fig. 3).

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 91

Figura 45. Leitura de vários valores e sua visualização pela ordem inversa

A alternativa para este tipo de situações é o uso de Tabelas, que não são mais do que uma lista de valores. Assim, para o exemplo da fig. 3 poderiamos armazenar os valores numa variável do tipo tabela e aceder aos valores pela ordem desejada (fig.4).

Figura 46. Armazenamento de vários valores numa tabela.

Valor 1

Saída

Programa

...

Variável 1

Valor 2

Valor 3

Valor 4

Valor 5

Valor n

Variável 2

Variável 3

Variável 4

Variável 5

Variável n

...

Valor 1

Saída

Programa

Variável Tabela

Valor 2

Valor 3

Valor 4

Valor 5

Valor n

...

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 92

6.2 - Tabela Unidimensional

6.2.1 - Introdução

Existem duas formas de declarar uma tabela em Java:

(1) <tipo> <variável> [ ] (2) <tipo> [ ] <variável>

Exemplos :

(1) int tab [ ] ; (2) int [ ] tab ;

Fazendo uma pequena revisão sobre as variáveis simples, estas :

• armazenam um só valor. • são criadas quando da sua declaração. • armazenam tipos primitivos, que são manipulados por valor.

As tabelas:

• são um agregado de valores, todos do mesmo tipo. • estão indexadas a partir de 0. • uma vez criadas possuem um tamanho fixo. • são criadas em java dinamicamente, ou seja, em tempo de execução. • o seu espaço é automaticamente reaproveitado quando deixam de estar referenciados.

6.2.2 - Passos para utilizar uma tabela

Os passos para utilizar uma tabela são três, declaração, instanciação e referenciação:

1) Declaração : Na declaração de uma tabela cria-se uma referência para um determinado tipo de dados. No exemplo que se segue cria-se uma referência para uma tabela de inteiros com qualquer dimensão, sendo a mesma iniciada com null.

int [] tab;

2) Instanciação : Na instanciação de uma tabela é definida a capacidade da mesma. No exemplo seguinte cria-se uma tabela com o nome tab, com uma capacidade para cinco inteiros.

null tab

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 93

tab = new int[5] ;

• Uma tabela em java é sempre criada dinamicamente com o operador new • O índice dos elementos começa em 0 e termina em tamanho –1, ou seja, uma tabela de tamanho

N é indexada de 0 a N-1. Caso se exceda a dimensão da tabela é gerada uma excepção. • Depois de instanciado podemos saber a sua dimensão consultando o atributo só de leitura

length ( exp: tab.length). • As tabelas de valores numéricos são inicializadas a zero.

A instanciação (criação) de uma tabela pode ser feita no momento de declaração, se se indicar o conteúdo.

int tab [ ] = {1,1,2,3,5,8,13,34}; // é criada uma tabela com // 8 elementos

3) Referenciação : tab[1] = 12; // o elemento com o índice 1 da tabela

// passa a armazenar o valor 123

tab 1 12

2 3

tab[0] tab[3]

tab[2] tab[1]

5 8 13 34

….. tab[7]

tab 1 1

2 3

tab[0] tab[3]

tab[2] tab[1]

5 8 13 34

….. tab[7]

tab

tab[0] tab[1] tab[2] tab[3] tab[4]

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 94

Exemplo do uso de tabela e variáveis simples

Uso Variável Simples Tabela Atribuição valor = 10.6; tab[3] = 10.6; Entrada valor =

scanTeclado.nextDouble(); tab[3]= scanTeclado.nextDouble();

Saída System.out.println(valor); System.out.println(tab[3]); Expressão x = valor / 2; x = tab[3] / 2; Comparação if (valor > 5.0); if (tab[3] > 5.0); Parâmetros Testa(valor); Testa(tab[3]); Exemplos de acesso aos elementos de uma tabela: Exemplo 1 Neste exemplo pretende-se calcular o valor médio da pluvisiosidade em 18 anos. Para tal, cria-se uma tabela que guarde 18 valores e preenchesse a tabela com os valores da pluvisiosidade: double [ ] pluv = new double [18];

pluv [0] = 30.55; pluv [1] = 23.94; ……. //restante valores Depois efectua-se a soma dos valores, que pode ser feita por duas formas : double total = pluv[0] + pluv[1] + pluv[2] + pluv[3] + pluv[4] + pluv[5] + pluv[6] + pluv[7] + pluv[8] + pluv[9] + pluv[10] + pluv[11] + pluv[12] + pluv[13] + pluv[14] + pluv[15] + pluv[16] + pluv[17]; ou double total = 0.0; for ( int ano = 0; ano < pluv.length; ano ++)

total = total + pluv[ano]; Nota : relembre-se que o índice do vector começa em 0 e pode ir até length-1 Com o valor da soma efectuado, podemos calcular a média e imprimir para o ecran o valor: System.out.println(“O valor média de pluviosidade é”+(total/pluv.length)); Exemplo 2

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 95

O exemplo seguinte tem como objectivo pedir ao utilizador o valor de cinco inteiros, imprimir no ecran os valores introduzidos, calcular a soma, a média e o valor máximo destes valores. import Le; public class MaxTotal{ public static void main(String[] args) { int n1[] = new int[5]; int soma=0; int max=0; //Ler array for(int i=0;i<5; i++) { n1[i]= scanTeclado.nextInt(); System.out.println(“Introduza um valor: “); } //Mostrar array for(int i=0;i<5; i++) System.out.println("i["+i+"]="+n1[i]); //Calcular máximo, total for(int i=0;i<5; i++){ soma+=n1[i]; if (max<n1[i]) max=n1[i]; } //Mostrar resultados System.out.println("Total:"+soma); System.out.println("Media:"+(float)soma/n1.length); System.out.println("Maximo:"+max); //Nota: na media é necessário fazer uma divisao de floats. }

Figura 47. Criação e preenchimento da tabela do exemplo 2.

3

1 1

Tabela criada com 5 elementos indexados de 0 a 4

Depois de uma iteração do ciclo

10

11

2

3

1

Depois de duas iterações do ciclo

Depois das cinco iterações do ciclo

0

1

2

3

4

índices

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 96

Atenção : acesso a elementos não existentes da tabela Considere o exemplo 2, do ponto 1.2.4, no qual é criado e preenchido um array de cinco elementos. Caso se tentasse aceder a um elemento inexistente, durante a execução do programa seria detectado um erro: n1 [5] = 4; //acesso a um índice que não existe O erro detectado seria: Java.lang.ArrayIndexOutOfBoundsException:19 At Teste.main(Test.java)

6.3 - Tabelas de Objectos

As tabelas de objectos não são mais do que tabelas em que cada elemento é uma referência a um objecto de uma determinada classe. Todas as tabelas de objectos são inicializadas a null. Na sequência da classe Aluno, imaginemos que se pretendia gerir uma turma de alunos, com funcionalidades como inserir, listar, procurar e apagar alunos. A solução seria criar uma tabela do tipo Aluno. Aluno [] tabelaAlunos ; Uma vez que se pretende gerir uma turma de alunos, deve-se criar uma classe Turma, que como atributo terá a tabela de alunos: public class Turma { private Aluno [ ] tabelaAlunos ; private int numAlunos; // número de alunos inscritos na turma private final static int MAXIMO_ALUNOS=20; //Lotação máxima } Quando se define uma classe, deve-se implementar os construtores da mesma. No caso da classe Turma serão definidos dois construtores. public Turma() { tabelaAlunos = new Aluno[MAXIMO_ALUNOS]; numAlunos=0; } public Turma(int max) { tabelaAlunos = new Aluno[max]; numAlunos=0; } No primeiro construtor, define-se que a tabela de alunos terá como dimensão o valor da constante MAXIMO_ALUNOS. No segundo construtor a dimensão da tabela de alunos será passada por argumento. Em ambos os construtores a variável numAlunos é inicializada a zero por não existirem alunos inscritos no início.

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 97

A funcionalidade inserir aluno na turma pode ser implementada da seguinte forma: public boolean insereAluno(Aluno a1) { if(tabelaAlunos.length>numAlunos) // testa se a tabela não está cheia { tabelaAlunos[numAlunos]=a1; // insere na tabela numAlunos++; // incrementa a variável num return true; } return false; } Outra forma de implementar este método sem a passagem de um objecto do tipo Aluno seria: public boolean insereAluno(String nome, int num, String curso,

int ano, char turma) { if(tabelaAlunos.length>numAlunos) { Aluno aluno = new Aluno(nome, num,curso, ano, turma); //inserir na tabela tabelaAlunos[numAlunos++]=aluno; return true; } return false; } Outra das funcionalidades requeridas é listar a informação contida na tabela, ou seja, lista os alunos inscritos na turma: public String listar( ) { String str=""; for(inti=0;i<tabelaAlunos.length && tabelaAlunos[i]!=null;i++) str= str+ i + " "+ tabelaAlunos[i].toString(); return str; } É de notar que quando se está a correr uma tabela de objectos, é necessário verificar se a posição corrente tem ou não conteúdo. tabelaAlunos[i]!=null é a expressão que verifica se a posição i da tabela de alunos é diferente de null.

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 98

Outra alternativa a este método: public String listar( ) { String str=""; for(inti=0;i<numAlunos;i++) str= str+ i + " "+ tabelaAlunos[i].toString(); return str; } Procurar um aluno na tabela, poderá ter duas implementações:

• Procura pelo numero de aluno • Procura por nome de aluno

public Aluno procuraAluno(int num ) { for(int i=0;i<tabelaAlunos.length && tabelaAlunos[i]!=null;i++) // verifica se o aluno na posição i tem o numero igual a num if(this.tabelaAlunos[i].getNumero()==num) return tabelaAlunos[i]; return null; } Na procura por número de aluno tem que se percorrer a tabela e para cada posição da mesma verificar se o número do aluno é igual ao num passado no argumento do método. Como num é do tipo primitivo inteiro usa-se o operador ==. public Aluno procuraAluno(String nome ) { for(int i=0;i<tabelaAlunos.length && tabelaAlunos[i]!=null;i++) // verifica se o aluno na posição i tem o nome igual a nome if(this.tabelaAlunos[i].getNome().equals(nome)) return tabelaAlunos[i]; return null; } Na procura por nome de aluno tem que se percorrer a tabela e para cada posição da mesma verificar se o nomedo aluno é igual ao nome passado no argumento do método. Como estamos perante variáveis do tipo String usa-se o método equals. str1.equals(str2) verifica se a str1 1 é igual à str2. A funcionalidade de apagar aluno é mais complexa de implementar. O algoritmo deste método é dividido em duas partes:

• Procura o índice da tabela onde se encontra o objecto a apagar. • Reconstrói a tabela a partir do índice encontrado.

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 99

public boolean apagarAluno(int num ) { boolean flag=true; int i,j; for(i=0;i<numAlunos && flag;i++) if(tabelaAlunos[i].getNumero()==num) { flag =false; } if( flag) return false; else { for(j=i-1; j<numAlunos-1;j++) tabelaAlunos[j]=tabelaAlunos[j+1]; tabelaAlunos[j]=null; } return true; } Para testar o funcionamento dos métodos pode-se utilizar a seguinte classe com o método main: public class Principal { public static void main(String[] args) { Turma tEIA= new Turma(15); Aluno aluno2 = new Aluno("João", 2133,"EI", 1, 'A'); System.out.println(tEIA.listar()); tEIA.insereAluno(aluno2); System.out.println(tEIA.listar()); tEIA.insereAluno("Ana", 2131,"EI", 1, 'A'); tEIA.insereAluno("Pedro", 2137,"EI", 1, 'A'); tEIA.insereAluno("Vitor", 2138,"EI", 1, 'A'); System.out.println(tEIA.listar()); Aluno a1= tEIA.procuraAluno(2133); System.out.println(a1); tEIA.apagarAluno(2133); System.out.println(tEIA.listar()); tEIA.apagarAluno(2131); System.out.println(tEIA.listar()); tEIA.apagarAluno(2138); System.out.println(tEIA.listar()); } }

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 100

O Output seria: tabelaAlunos [0]= Nome:João Numero :2133 curso : EI Ano1 tabelaAlunos [0]= Nome:João Numero :2133 curso : EI Ano1 tabelaAlunos [1]= Nome:Ana Numero :2131 curso : EI Ano1 tabelaAlunos [2]= Nome:Pedro Numero :2137 curso : EI Ano1 tabelaAlunos [3]= Nome:Vitor Numero :2138 curso : EI Ano1 Nome:João Numero :2133 curso : EI Ano1 tabelaAlunos [0]= Nome:Ana Numero :2131 curso : EI Ano1 tabelaAlunos [1]= Nome:Pedro Numero :2137 curso : EI Ano1 tabelaAlunos [2]= Nome:Vitor Numero :2138 curso : EI Ano1 tabelaAlunos [0]= Nome:Pedro Numero :2137 curso : EI Ano1 tabelaAlunos [1]= Nome:Vitor Numero :2138 curso : EI Ano1 tabelaAlunos [0]= Nome:Pedro Numero :2137 curso : EI Ano1 Em seguida serão apresentados mais exemplos sobre tabelas de objectos. Exemplos: Tabela de Strings No exemplo em seguida apresentado é declarada uma tabela de Strings que não é mais do que uma tabela em que cada elemento da tabela é uma referência a uma String. final int NUM_NOMES = 5; // Declaração e instanciação String[] nome = new String [NUM_NOMES ] ; // Inicialização ou Atribuição nome[0] = "Smith"; nome[1] = "Jones"; nome[2] = "Miller"; nome[3] = "Luis"; nome[4] = "Gonzales"; // Saída System.out.println ("Resultado:"); for (int indice = 0; indice < nome.length; indice ++) System.out.println (“nome[“ + indice + "]: " + nome[indice]);

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 101

Tabela de Objectos da classe pessoa O código da classe pessoa, apresenta-se em seguida: class Pessoa { String nome; int idade; String BI; public Pessoa (String pfN, String pfC, int pfI) { nome = pfN; BI = pfC; idade = pfI; } public void apresentar() { System.out.println(“Meu nome é ” + nome); System.out.println(“Tenho ”+ idade + “anos”); } public String getBI() { return BI; } public String toString() { return (“nome=“+nome+”com “+idade+”anos”); } } A classe seguinte testa a utilização da classe pessoa. public class Teste { public static void main (String args[]) { Pessoa Pedro; Pessoa Nuno; Pedro = new Pessoa(“Pedro Martins”,“403.234.567”, 34); Nuno = Pedro; Pedro.apresentar(); Nuno.apresentar(); System.out.println(“O BI de Pedro e “+Pedro.getBI()); } }

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 102

Em seguida apresenta-se o código onde se cria uma tabela de objectos da classe pessoa, que é uma tabela em que cada elemento é uma referência a um objecto da classe pessoa. public class TabelaDeObjectos { public static void main(String[] args) { //Declaração e Instanciação da tabela Pessoa[ ] grupo = new Pessoa [4]; //Inicialização dos elementos da tabela (Atribuição) grupo[0] = new Pessoa("Pedro Sousa", "403234567",34); grupo[1] = new Pessoa("António Pereira", "233544325",37); grupo[2] = new Pessoa("João Silva", "763234567",40); grupo[3] = new Pessoa("Joaquim Feliz", "213456567",20); //Saída System.out.println("Conteúdos de cada elemento da tabela:"); for (int pessoa = 0; pessoa < 4; pessoa ++) System.out.println((pessoa + 1) + "ª Pessoa do Grupo: " + grupo[pessoa].toString ); } }

Figura 48. Exemplo gráfico dos resultados obtidos com o código anterior

Tabela dinâmica No exemplo apresentado em seguida será criada uma tabela dinâmica, lida uma lista de números inteiros terminada por 0 e depois com os valores lildos calculada a média e o valor máximo.

import Le; public static void main(String args[]) { //Declaração de uma tabela de inteiros com // dimensão ainda indefinida int tab[ ]={}; int soma=0; int max=0; int i=1;

Pedro Sousa

António Pereira

João Silva Joaquim Feliz

grupo[0] grupo[1] grupo[2] grupo[3]

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 103

//Ler 1º valor System.out.print(“Insira o 1º inteiro:> ”); int n = scanTeclado.nextInt(); while (n!=0) { //criar tabela temporária int tabTemp[]=new int[tab.length+1]; //copiar valores for(int j=0;j<tab.length;j++) tabTemp[j]=tab[j]; //inserir novo valor tabTemp[tabTemp.length-1]=n; //colocar a tabela temporária na definitiva tab = tabTemp; System.out.print(“Insira o ” + j + ”º inteiro:> ”); n = scanTeclado.nextInt(); } //Mostrar tabela for(i=0; i<tab.length; i++) System.out.println(“tab[“ + i + "]="+ tab[i]); //Calcular o valor máximo e a soma total for(i=0; i<tab.length; i++) { soma+ = tab[i]; if (max < tab[i]) max = tab[i]; } //Mostrar resultados System.out.println("Total:"+soma); //Nota: na media é necessário fazer uma divisao de floats. System.out.println("Media:"+(float)soma/n1.length); System.out.println("Maximo:"+max); }

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 104

Lista Telefónica No exemplo seguinte pretende-se criar uma lista telefónica. Para tal, cria-se a classe Contacto, cujos atributos são o nome e o telefone da pessoa: public class Contacto { //Atributos String nome; int telefone; //Construtores public Contacto(String nomeContacto, int telefoneContacto) { nome=nomeContacto; telefone=telefoneContacto; } //Métodos public String mostrarContacto() { return nome + " - " + telefone; } public int obterTelefone() { return telefone; } public String obterNome() { return nome; } } Em seguida veremos a classe Lista telefónica na qual é manipulado uma tabela de objectos do tipo Contacto: public class ListaTelefonica { //Atributos private static final int MAXCONTACTOS= 20; private Contacto contactos []; private int nContactos=0; //Construtores public ListaTelefonica(){ contactos = new Contacto[MAXCONTACTOS]; }

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 105

//Métodos public void adicionar() { String nome; int telefone; System.out.println("Introduza o nome:"); nome= scanTeclado.next(); System.out.println("Introduza o telefone:"); telefone= scanTeclado.nextInt(); Contacto c = new Contacto(nome,telefone); contactos[nContactos]=c; nContactos++; } public void mostrar(){ for ( int i=0; i<nContactos; i++) System.out.println(contactos[i].mostrarContacto()); } public void procurar(){ System.out.println("Qual o telefone:"); int telefone= scanTeclado.nextInt(); int i=0; while(i<nContactos && contactos[i].obterTelefone()!=telefone) i++; if (i!=nContactos) System.out.println(contactos[i].mostrarContacto()); else System.out.println("O número não se encontra na lista."); } public void ordenar(){ quickSort(0, nContactos-1); } private void quickSort( int pri, int ult) { int i = pri; int j = ult; if (pri > ult) return; String pivot = contactos[(pri + ult)/2].obterNome(); do { while (contactos[i].obterNome().compareToIgnoreCase(pivot) < 0) i++; while (contactos[j].obterNome().compareToIgnoreCase(pivot) > 0) j--;

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 106

if (i <= j) trocaContactos(i++, j--); } while (i <= j) ; quickSort(pri, j); quickSort(i, ult); } private void trocaContactos(int i, int j){ Contacto tmp = contactos[i]; contactos[i] = contactos[j]; contactos[j] = tmp; } } public class ExemploListaTelefonica { public static void main(String[] args) { ListaTelefonica listaTel = new ListaTelefonica(); int seleccao; do { System.out.println("Organizer"); System.out.println(""); System.out.println("1 - Adicionar"); System.out.println("2 - Mostrar"); System.out.println("3 - Procurar"); System.out.println("4 - Ordenar"); System.out.println("5 - Sair"); System.out.println("_______________________"); System.out.println("Qual a sua escolha?"); seleccao = scanTeclado.nextInt(); switch(seleccao){ case 1: listaTel.adicionar(); break; case 2: listaTel.mostrar(); break; case 3: listaTel.procurar(); break; case 4: listaTel.ordenar(); break; case 5:

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 107

System.out.println("Adeus."); break; default: System.out.println("Opção errada. Tente de Novo."); break; } } while(seleccao != 5); } }

6.4 - Passagem de tabelas como parâmetros de métodos

Uma tabela pode ser passada como parâmetro a um método. O que é passado como parâmetro (por valor) é a referência da tabela, o que significa a alteraração de um elemento da tabela dentro do método, altera a tabela original. Também é possível passar como parâmetro um elemento de uma tabela, desde que se sigam as regras referentes ao seu tipo. É possível passar como parâmetro um elemento de uma tabela, desde que se sigam as regras referentes ao seu tipo. Exemplo:

public class programa { public static void main(String args[]) { int [] array = new int[2]; array[0]=12; array[1]=10; for(int i=0;i<array.length;i++) System.out.println(array[i]); metodo_1(array); for(int i=0;i<array.length;i++) System.out.println(array[i]); metodo_2(array[1]); for(int i=0;i<array.length;i++) System.out.println(array[i]); } public static void metodo_1(int [] varray) { for(int i=0;i<array.length;i++) array[i]=array[i]+1; } public static void metodo_2(int var) {

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 108

System.out.println(“O valor recebido é :”+var); } } O output do código atrás apresentado, à luz dos conceitos introduzidos é: 12 10 13 11 O valor recebido é 11. 13 11

6.5 - Tabela Multidimensional

Uma tabela uni-dimensional representa uma lista de valores enquanto que uma tabela multidimensional representa uma matriz, com linhas e colunas. Cada elemento de uma tabela multidimensional é referenciado usando dois índices. Em Java, uma tabela multidimensional é uma tabela de tabelas, ou seja é uma tabela uni-dimensional em que cada elemento é uma referência para um objecto do tipo tabela. Declaração:

<tipo> [ ] [ ] <variável> Exemplo int [ ] [ ] tab; O código acima declara tab como uma tabela bidimensional de inteiros ou como uma tabela de tabelas, em que apenas se cria uma referência. A inicialização é que cria a tabela com os comprimentos respectivos:

1) tab = new int [2] [3]; ou 2) tab [][]={1,2,3} {4,5,6};

Para percorrer a tabela usam-se ciclos for encadeados.

tab[0] 1

2 3

4

5 6

tab[1]

tab tab[0][0]

tab[1][2]

tab[0][2]

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 109

Exemplo public class Matriz { public static void main(string args[]) { int tab[][] = {{ 1, 2, 3 }, { 4, 5, 6 }}; for(int i = 0; i < tab.length; i++) for(int j = 0; j < tab[i].length; j++) System.out.print("tab[" + i + "][" + j + "] = " + tab[i][j]); } } O Java é uma linguagem fortemente tipada, sendo portanto o número de dimensões da matriz e o tipo dos elementos são definidos. O número de elementos em cada dimensão pode variar e o conteúdo dos elementos de uma tabela pode ser de quaisquer objectos ou tipos primitivos. Exemplo O exemplo seguinte mostra uma matriz 3D de vectores de comprimento variado. public class Ex { public static void main(string args[]) {

Random gerador = new Random(); Integer a3[][][] = new Integer[gerador.nextInt(7)][][];

for(int i = 0; i < a3.length; i++) { a3[i] = new Integer[gerador.nextInt(7)][]; for(int j = 0; j < a3[i].length; j++) { a3[i][j] = new Integer[gerador.nextInt(5)]; for(int k = 0; k < a3[i][j].length; k++) a3[i][j][k] = new Integer(i*j+k); } } for(int i = 0; i < a3.length; i++) for(int j = 0; j < a3[i].length; j++) for(int k = 0; k < a3[i][j].length; k++) System.out.print("a3["+i+"]["+j+"]["+k+"] = " + a3[i][j][k]); } }

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 110

6.6 - Classe Vector

6.6.1 - Introdução

A classe Vector faz parte do package java.util e funciona de forma idêntica a uma tabela, permitindo a armazenamento de valores e a referência a estes através de um índice. A grande diferença entre uma tabela e um objecto do tipo Vector é que este pode crescer e diminuir dinamicamente em tamanho, enquanto que uma tabela tem sempre um tamanho fixo. Outra diferença consiste no facto de um objecto do tipo vector não ser declarado para guardar um tipo de valor. Um objecto do tipo Vector gere uma lista de referências para a classe Object, permitindo assim guardar qualquer tipo de valor.

6.6.2 - Alguns métodos da classe Vector

Método Descrição Vector ( ) Cria um vector vazio void addElement (Object obj) Adiciona o objecto especificado ao fim

do vector void insertelementAt (Object obj, int index) Adiciona o elemento no índice

especificado Object remove ( int index) Remove um objecto do índice

especificado e retorna-o boolean removeElement (Object obj) Remove a primeira ocorrência do

objecto especificado. void removeElementAt(int index) Remove um objecto do índice

especificado void clear ( ) Remove todos os elementos do vector boolean contains (Object obj) Retorna true se o objecto está no vector int indexOf (Object obj) Retorna o índice do objecto

especificado. Retorna -1 caso o objecto não exista.

Object elementAt (int index) Retorna o Objecto no indice especificado

boolean isEmpty ( ) Retorna true se o vector estiver vazio int size ( ) Retorna o número de elementos do

vector Nota: Para mais informações sobre os métodos disponibilizados por esta classe, consultar a documentação do Java. Exemplo Neste exemplo será criado um objecto da classe Vector que armazenará nomes. Serão depois aplicadas algumas operações ao vector, como inserir, remover, verificar que elemento está num determinado índice.

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 111

public class Nomes { public static void main ( String [] args) { Vector nomes = new Vector( ); nomes.addElement(“Ricardo”); nomes.addElement(“João”); nomes.addElement(“Nuno”); nomes.addElement(“Daniel”); System.out.println(nomes); nomes.removeElement(“João”); System.out.println(nomes);

System.out.println(“No índice 1: “ + nomes.elementAt(1)); nomes.insertAt(“Carlos”,2);

System.out.println(“Tamanho do vector “ + nomes.size()); }

} Resultado de saída do exemplo Ricardo, João, Nuno, Daniel Ricardo, Nuno, Daniel No índice 1: Nuno Tamanho do vector 4

6.7 - Exercícios Práticos

Exerc.1 – Escreva um programa que preencha uma tabela com os valores inteiros gerados aleatoriamente e imprima todos os valores da tabela. Acrescente depois as seguintes funcionalidades ao seu programa:

• Indicar quantos valores negativos estão guardados na tabela • Imprimir os valores positivos da tabela • Indicar o maior valor da tabela • Substituir todos os valores divisíveis por 3 pelo valor zero • Indicar a posição do menor valor da tabela

Exerc.2 - Implemente um método que retorna o produto dos elementos de uma tabela. A assinatura do método é a que se segue:

static double produto(int [ ] x) Exerc.3 - Implemente um método que retorna o menor valor de uma tabela. A assinatura do método é a que se segue:

static double menorValor(double [ ] x)

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 112

Exerc.4 - Escrever um método que, dada uma sequência de n valores inteiros, retorne a diferença entre os valores máximo e mínimo da sequência. Exerc.5 - Escrever um método que retire todas ocorrências de um caracter carC de uma string. A assinatura do método é a que se segue:

static String remove(String s, char carC ) Exerc.6 - Escrever um programa que converta uma string numa tabela de caracteres. Exerc.7 - Escrever um método que receba um número e uma tabela e devolva a posição na tabela onde este número ocorra ou o valor -1 no caso do número não existir na tabela. A assinatura do método é a que se segue:

static int indiceValor(int [ ] tabela, int valor)

Exerc.8 - Escrever um método que inverta a ordem dos elementos de uma tabela de inteiros, passada como parâmetro. Exerc.9 - Escrever um método que devolva a posição da última ocorrência do valor máximo de uma tabela de valores do tipo double. Exerc.10 - Escrever um método que receba duas tabelas e retorne true se as tabelas são iguais. Exerc.11 - Escrever um programa que, para um dada tabela de inteiros A, construa uma tabela P formada pelos índices dos elementos pares de A. Exemplo: Para A = ( 1 3 6 7 8 ), o programa deve construir P = ( 3 5 ). Exerc.12- Escrever um método (e um programa que exercite tal método) que determine se os elementos de uma tabela encontram-se em ordem decrescente ou não. Exerc.13 - Escrever um programa que, dada uma sequência de n valores inteiros (gerados aleatoriamente) que representam o resultado de n lançamentos de um dado, determine o número de ocorrências de cada face na sequência analisada. Exerc.14 - Dada uma sequência de n números reais, fazer um programa que determine os números que compõem a sequência e a frequência de tais números na sequência dada. Exemplo: n = 10 Sequência: 3.2 8.1 2.5 3.2 7.4 8.1 3.2 6.3 7.4 3.2 Saída: Num Freq 3.2 4 8.1 2 2.5 1 7.4 2 6.3 1 Exerc.15 - Escrever um programa que determine o maior valor em uma matriz de valores inteiros com n>0 linhas e m>0 colunas. Em seguida altere o programa anterior para indicar todas as posições da matriz em que se encontra tal valor máximo.

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 113

Exerc.16 - Implemente um método que retorne o cálculo do produto externo entre duas matrizes. A matriz resultante calcula-se da seguinte forma p[i][j]=x[i]*y[j], onde x e y são as tabelas de entrada. A assinatura do método é:

static double[][] productoExterno(double[] x, double[] y) Exerc.17 - Escrever um programa que inicialmente lê um número inteiro N. Se o valor introduzido for menor que 2 (dois) finalizar o programa. Caso contrário, cria dinamicamente uma matriz de inteiros NxN. Em seguida lê um valor para cada posição da matriz e, no final, mostrar se a matriz possui algum valor repetido. Exerc. 18 - Defina uma classe WebSite caracterizada pelo nome, endereço e lista de temas que se podem encontrar no mesmo. Implemente as seguintes funcionalidades a esta classe:

• Determinação de quantos temas possui o website • Verificar se um determinado tema existe no website • Adicionar um tema • Remover um tema

Elabore uma classe CatalogoWeb que implementa um arquivo sobre webSites e cujas funcionalidades são:

• Determinação do número total de websites do catálogo • Listar os Websites que tratam um determinado tema T • Remover um website

Exerc. 20 – Construa uma classe estática que tem como objectivo conter métodos utilitários para a manipulação de tabelas. Esses métodos são os já criados nos exercícios 2,3,8 e 10.

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 114

7 - Algoritmos de Procura/Pesquisa

7.1 - Introdução

A procura de informação é uma actividade quotidiana: procuramos números em listas telefónicas, palavras em dicionários, etc. Estudaremos em seguida dois métodos para procurar um elemento numa tabela:

• A procura sequencial. • A procura binária.

A procura de informação é frequentemente executada em tabelas. Ao longo deste capítulo vamos utilizar uma tabela preenchida. Vamos para tal fazer uso de uma classe (Tabela) que possui um método (preenche) que preenche uma tabela, passada como parâmetro, com valores inteiros gerados aleatoriamente entre 0 e 100. O código da classe é em seguida apresentado: import java.util.Random; class Tabela { public static void preenche(int tabela[]){ Random random = new Random(); for (int i=0; i < tabela.length; i++) tabela[i] = random.nextInt(100); } public static void imprime(int tabela[]){ for (int i=0; i < tabela.length; i++) System.out.println(" "+i+":"+ tabela[i]+"; "); System.out.println(); } }

7.2 - Procura Sequencial

7.2.1 - Simples

Uma forma simples de procurar consiste em: • Começar no inicio da tabela. • Comparar sucessivamente o elemento procurado com o elemento da tabela. • Repetir o processo até encontrar o elemento ou atingir o fim da tabela.

Como a tabela é percorrida sequencialmente, o algoritmo é denominado por procura sequencial.

No exemplo seguinte pretende-se saber qual a posição que o valor 75 (se existir) ocupa na tabela de números.

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 115

Posição 0 Compara-se 75 com 10 → São diferentes Incremento a posição Posição 1 Compara-se 75 com 20 → São diferentes Incremento a posição Posição 2 Compara-se 75 com 75 → São iguais Parar a procura

O valor procurado é achado e ocupa a terceira posição da tabela. O próximo exemplo utiliza um programa que preenche uma tabela com números gerados aleatoriamente (entre 0 e 100) e permite, em seguida, procurar números que foram inseridos. public class ProcuraSequencial{ public static int procura (int tab[], int valor) { int i = 0; while (i < tab.length && tab[i] != valor ) i++; if ( i != tab.length) return(i); // retorna indice; else return(-1); } public static void main(String[] args){ int tabela[] = new int[100]; Tabela.preenche(tabela); System.out.println("Resultado:"+procura(tabela,67); System.out.println("Resultado:"+procura(tabela,33)); System.out.println("Resultado:"+procura(tabela,1)); System.out.println("Resultado:"+procura(tabela,101)); } } O método procura retorna o índice do valor na tabela se encontrar o valor, caso contrário retorna -1. Note-se que no ciclo correspondente à procura propriamente dita,

10 20 75 9 4 3

0 1 2 4 3 5 Índice

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 116

while (i < tab.length && tab[ i ] != valor ) { tem de se efectuar continuamente dois testes:

• verificar se o valor desejado foi encontrado e • verificar se o fim da tabela foi atingido.

Embora a primeira verificação seja essencial a segunda seria desnecessária se pudesse garantir que o valor a procurar se encontrava na tabela.

7.2.2 - Com Sentinela

Uma técnica utilizada para prescindir do segundo teste consiste em utilizar um denominado valor sentinela. Um valor sentinela é um valor especial que inserimos na tabela para garantir que a procura tem sucesso. Neste caso trata-se de inserir o valor procurado a seguir ao último elemento da tabela. A utilização de um valor sentinela exige a existência de uma posição adicional na tabela para armazenar o valor sentinela. A primeira operação a efectuar, ainda antes da procura, é a inserção do valor sentinela no final da tabela. Se no fim da procura o valor encontrado for o sentinela, então o valor procurado não existe na tabela. No exemplo seguinte procede-se a implementação da procura sequencial com sentinela, utilizando um programa que preenche uma tabela com números gerados aleatoriamente (entre 0 e 100) e permite, em seguida, procurar números que foram inseridos. public class ProcuraSequencialSentinela { public static int procura(int tab[], int valor){ int i = 0; tab[tab.length-1] = valor; //SENTINELA while (tab[ i ] != valor ) i++; if ( i != tab.length-1) return(i); else return(-1); } public static void main(String[] args){ int tab[] = new int[101]; Tabela.preenche(tabela); System.out.println("Resultado:"+procura(tab,67)); System.out.println("Resultado:"+procura(tab,33)); System.out.println("Resultado:"+procura(tab,1)); System.out.println("Resultado:"+procura(tab,102); } }

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 117

7.3 - Procura Binária

A procura sequencial é muito simples, mas pode exigir a inspecção de todos os elementos da tabela. Isto acontece sempre que o elemento que estamos a procurar não se encontra na tabela. A procura binária é uma alternativa mais eficaz, mas exige que os elementos sobre os quais a procura está a ser efectuada se encontrem ordenados. O algoritmo é o seguinte:

1. Encontramos o meio da tabela. 2. Consideramos último o elemento da 1ª metade da tabela. 3. Se o elemento procurado é menor do que o último o elemento da 1ª metade da tabela, podemos garantir

que o procurado não se encontra na 2ª metade da tabela. 4. Repetimos então processo para a 1ª metade da tabela. 5. Se o elemento procurado é maior do que o último o elemento da 1ª metade da tabela, podemos garantir que

o procurado não se encontra na 1ª metade da tabela. 6. Repetimos então o processo para a 2ª metade da tabela. 7. Se o elemento no meio da tabela for igual ao procurado a procura termina. 8. Note-se que em cada passo a procura binária reduz o número de elementos a considerar para metade

O próximo exemplo utiliza um programa que lê 100 números e permite, em seguida, procurar os números que foram inseridos. public class ProcuraBinaria { public static int procuraBinaria(int tab[], int valor) { boolean achou = false; int alto = tab.length - 1; int baixo = 0; int meio = alto/2; while (!achou && alto >= baixo ) { if (valor == tab[meio ]) achou = true; else if (valor < tab[meio ]) alto = meio - 1; else baixo = meio + 1; meio = (alto + baixo )/2; } return((achou ) ? meio : -1); } public static void main(String[] args) {

int tabela[] = new int[100 for (int i=0; i < tabela.length; i++) tabela[i] = i;

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 118

System.out.println("Resultado:"+procuraBinaria (tabela,67)); System.out.println("Resultado:"+procuraBinaria (tabela,33)); System.out.println("Resultado:"+procuraBinaria (tabela,1)); System.out.println("Resultado:"+procuraBinaria (tabela,101)); } } Exemplo (Pesquisa de um valor inexistente na tabela)

Figura 49. Pesquisa binária de um valor inexistente na tabela.

1 3 3 5 7 8 92

baixo

(>x) altobaixo meio

(>x)

1ª iteração

2ª iteração

altobaixo meio

(<x) 3ª iteração

altobaixo

4ª iteração

v: x:

5 7 8 91 3 3

3 3 5 7 8 91

1 3 3 5 7 8 9

Valor a Procurar

O valor 2 não existe na tabela

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 119

public static int procuraBinaria (int tab[], int valor) { boolean achou = false; int alto = tab.length - 1; int baixo = 0; int meio = alto/2; while (!achou && alto >= baixo ){ if (valor == tab[meio ]) achou = true; else if (valor < tab[meio ]) alto = meio - 1; else baixo = meio + 1; meio = (alto + baixo )/2; } return((achou ) ? meio : -1); } Exemplo (Pesquisa de um valor existente na tabela)

Figura 50. Pesquisa binária de um valor existente na tabela

7.4 - Exercícios práticos

Exerc.1 - Implemente o método máximo que retorna o maior valor dos elementos da tabela x. Utilize o algoritmo de procura sequencial.

1 3 3 5 7 8 9 1

baixo altomeio

(>x)alto baixo meio

(>x)

1ª iteração

2ª iteração

alto baixo meio

(<x)3ª iteração

v: x:

5 7 8 9 1 3 3

3 3 5 7 8 9 1

Valor a Procurar

O valor 1 existe na tabela

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 120

Exerc.2 - Implemente o método mínimo que retorna o índice do elemento de menor valor da tabela tabF. A assinatura do método é

public static int minimo(float[ ] tabF).

Exerc.3 - Implemente o método procuraCar que retorna o índice da primeira ocorrência do caracter c1 na tabela tabCar. Utilize o método de procura binária. A assinatura do método é:

public static int procuraCar(car[ ] tabCar, car c1) Exerc.4 - Temos uma tabela com as temperaturas médias ao longo dos dias de mês. Queremos saber para um determinado mês:

1. Qual foi a temperatura mais baixa 2. Em que dia ocorreu a temperatura mais elevada 3. Qual foi a diferença entre a temperatura mais baixa e a temperatura mais alta.

Exerc.5 - Implemente o método procuraFloat que procura na tabela v, que tem como critério de paragem o valor de s, se esta contem o elemento x. Caso a procura seja realizada com sucesso retorna o índice do elemento, senão retorna –1. assinatura do método é

public static int procuraInteiro(int[] v, int x, int s)

Exerc.6 - Um sistema de controlo de presenças ligado ao sistema de marcação de ponto, mantém uma lista de todos os trabalhadores que num determinado momento se encontram dentro da empresa. É necessário implementar um método que dado o nome de uma pessoa, ele nos valide se esta pessoa se encontra dentro da empresa ou não. Utilize a procura binária na implementação desta função. Nota: a lista é terminada com a palavra “ * ‘” A assinatura do método é: public static boolean procuraPessoa(String[ ] v)

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 121

8 - Algoritmos de Ordenação

8.1 - Introdução

Um conjunto de elementos é normalmente ordenado para facilitar a procura. Ordenamos as coisas para facilitar a procura e não por sermos naturalmente arrumados. Imagine que teria de procurar o número de telefone de um amigo numa lista telefónica que não estivesse ordenada alfabeticamente. Seria caótico certamente. Em programação, a utilização de tabelas ordenadas permite escrever algoritmos de procura mais eficientes. Nos algoritmos de ordenação que serão em seguida introduzidos, vamos supor que pretendemos ordenar uma sequência de inteiros com um máximo de 100 elementos. Com o objectivo de separar algumas operações que se repetem ao longo dos exemplos de ordenação, vamos apresentar de seguida uma classe (Tabela) que permite realizar as seguintes funções, sobre uma tabela:

• Preenchimento de uma tabela com valores inteiros, não ordenados, gerados aleatoriamente. • Troca de elementos de uma tabela. • Impressão dos elementos de uma tabela.

import java.util.Random; class Tabela { //(1) preenche uma tabela public static void preenche(int tabela[]) { Random random = new Random(); for (int i=0; i < tabela.length; i++) tabela[i] = random.nextInt(100); } //(2) troca as posições de dois elementos da tabela public static void troca(int tabela[], int x, int y){ int tmp; tmp = tabela[x]; tabela[x] = tabela[y]; tabela[y] = tmp; } //(3) Imprime a tabela public static void imprime(int tabela[]) { for (int i=0; i < tabela.length; i++) System.out.println(" "+i+": "+ tabela[i]+" ; "); System.out.println(); }

// O método main vai variar para cada implementação }

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 122

8.2 - BubbleSort

Este algoritmo consiste em: • Percorrer os elementos a ordenar, comparando elementos adjacentes e trocando os pares de

elementos que se encontram fora de ordem. • Até que se tenha efectuado uma passagem completa em que não haja nenhuma troca de posições.

Note que a tabela encontra-se ordenada quando se efectua uma passagem completa em que nenhum par de elementos trocou de posição. De um modo geral uma única passagem pelo conjunto de elementos não ordena a tabela. O tempo de execução é proporcional a n2, onde n é o numero de elementos a serem ordenados. Consideremos a seguinte tabela, onde se aplicará o algoritmo BubbleSort: Veremos a evolução da posição dos elementos ao longo das passagens e da variável trocou que permite saber se ao longo da passagem houve trocas de posição.

Primeira passagem trocou = false 4 8 17 3 11 2 4 8 17 3 11 2 4 8 3 17 11 2 (trocou=true) 4 8 3 11 17 2 (trocou=true) 4 8 3 11 2 17 (trocou=true) Segunda passagem trocou = false 4 8 3 11 2 17 4 3 8 11 2 17 (trocou=true) 4 3 8 11 2 17 4 3 8 2 11 17 (trocou=true) 4 3 8 2 11 17

Terceira passagem trocou = false 3 4 8 2 11 17 (trocou=true) 3 4 8 2 11 17 3 4 2 8 11 17 (trocou=true) 3 4 2 8 11 17 3 4 2 8 11 17 Quarta passagem trocou = false 3 4 2 8 11 17

4 8 17 3 11 2

0 1 2 4 3 5 Índice

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 123

3 2 4 8 11 17 (trocou=true) 3 2 4 8 11 17 3 2 4 8 11 17 3 2 4 8 11 17 Quinta passagem trocou = false 2 3 4 8 11 17 (trocou=true) 2 3 4 8 11 17 2 3 4 8 11 17 2 3 4 8 11 17 2 3 4 8 11 17 Sexta passagem trocou = false 2 3 4 8 11 17 2 3 4 8 11 17 2 3 4 8 11 17 2 3 4 8 11 17 2 3 4 8 11 17 trocou == false – Termina!

O código da implementação do algoritmos BubbleSort é apresentado em seguida: public class OrdenacaoBubbleSort { public static void bubbleSort(int tabela[ ] ) { boolean houveTroca; do { houveTroca = false; for (int j = 0; j < tabela.length-1; j++) if (tabela[j] > tabela[j+1]){ Tabela.troca(tabela, j, j+1); houveTroca = true; } }while (houveTroca); } public static void main(String[] args) { int tabela[] = new int[100]; Tabela.preenche(tabela); //preenche tabela Tabela.imprime(tabela); //imprime tabela antes da ordenação bubbleSort(tabela); //ordena tabela Tabela.imprime(tabela); //imprime tabela depois de ordenada } }

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 124

8.3 - ShellSort

A ordenação ShellSort é uma variante da ordenação BubbleSort e consiste em comparar e trocar, não elementos adjacentes, mas sim elementos separados por um certo intervalo. Como intervalo inicial considera-se metade do número de elementos a ordenar. Após uma ordenação completa, do tipo BubbleSort, com o intervalo inicial, esse intervalo é dividido ao meio e o processo repete-se para o novo intervalo. Este processo repete-se até que o intervalo seja 1 (correspondente a uma ordenação por BubbleSort). Note que a ordenação ShellSort é mais eficiente (mais rápida) do que a ordenação BubbleSort porque as primeiras passagens consideram apenas um subconjunto dos elementos a ordenar e as últimas passagens já os encontram parcialmente ordenados. Consideremos a tabela que foi usada no exemplo do Bubblesort: Vejamos a evolução da posição dos elementos ao longo das passagens, da variável trocou que permite saber se ao longo da passagem houve trocas de posição e da variável intervalo que define a distância entre elementos comparados.

Passagem 1 Intervalo=3 trocou=False 3 8 17 4 11 2 (trocou=true) 3 8 17 4 11 2 3 8 2 4 11 17 (trocou=true) Passagem 2 Intervalo=3 trocou=False 3 8 2 4 11 17 3 8 2 4 11 17 3 8 2 4 11 17 Passagem 3 Intervalo=1 trocou=False 3 8 2 4 11 17 3 2 8 4 11 17 (trocou=true) 3 2 4 8 11 17 (trocou=true) 3 2 4 8 11 17 3 2 4 8 11 17 Passagem 4

4 8 17 3 11 2

0 1 2 4 3 5 Índice

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 125

Intervalo=1 trocou=False 2 3 4 8 11 17 (trocou=true) 2 3 4 8 11 17 2 3 4 8 11 17 2 3 4 8 11 17 2 3 4 8 11 17 Passagem 5 Intervalo=1 trocou=False 2 3 4 8 11 17 2 3 4 8 11 17 2 3 4 8 11 17 2 3 4 8 11 17 2 3 4 8 11 17

O código da implementação do algoritmo ShellSort é apresentado em seguida: public class OrdenacaoShell { public static void shell (int tabela[ ] ) { boolean nenhumaTroca; int intervalo; intervalo = tabela.length / 2; do { do { nenhumaTroca = true; for (int j = 0; j < tabela.length-intervalo; j++) if (tabela[j] > tabela[j+intervalo]) { Tabela.troca(tabela, j, j+intervalo); nenhumaTroca = false; } }while (!nenhumaTroca); intervalo = intervalo / 2; }while ( intervalo > 0); } public static void main(String[] args){ int tabela[] = new int[100]; Tabela.preenche(tabela); //preenche tabela Tabela.imprime(tabela); //imprime tabela antes da ordenação shell(tabela); //ordena tabela

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 126

Tabela.imprime(tabela); //imprime tabela depois de ordenada } }

8.4 - Ordenação por selecção

A ordenação por selecção consiste em percorrer os elementos a ordenar e, em cada passagem, colocar um elemento na sua posição correcta:

o Na 1ª passagem coloca-se o menor elemento na sua posição correcta. o Na 2ª passagem coloca-se o segundo menor. o E assim sucessivamente.

Consideremos novamente a mesma tabela: Vejamos a evolução da posição dos elementos ao longo das passagens:

Primeira passagem (4 8 17 3 11 2) 2 8 17 3 11 4 Segunda passagem (2 8 17 3 11 4) 2 3 17 8 11 4 Terceira passagem (2 3 17 8 11 4) 2 3 4 8 11 17 Quarta passagem (2 3 4 8 11 17) 2 3 4 8 11 17

O código da implementação do algoritmo é apresentado em seguida: public class OrdenacaoSeleccao { void selectionSort(int numbers[]) { int i, j; int min, temp; for (i = 0; i < numbers.length-1; i++) { min = i; for (j = i+1; j < numbers.length; j++) { if (numbers[j] < numbers[min]) min = j; }

4 8 17 3 11 2

0 1 2 4 3 5 Índice

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 127

Tabela.troca(numbers, i, min); } } public static void main(String[] args) { int tabela[] = new int[100]; Tabela.preenche(tabela); //preenche tabela Tabela.imprime(tabela); //imprime tabela antes da ordenação selectionSort(tabela); //ordena tabela Tabela.imprime(tabela); //imprime tabela depois de ordenada } }

8.5 - Algoritmo QuickSort

É um algoritmo recursivo baseado na técnica divide and conquer!

o Escolher um elemento arbitrário (x) da tabela (chamado pivot) o Passo de Divisão

Dividir os restantes em dois grupos (esquerdo e direito). O grupo esquerdo é composto pelos elementos menores ou iguais que o elemento pivot. O grupo direito é composto pelos elementos maiores que o elemento pivot. O elemento pivot é colocado entre os dois grupos.

o Passo Recursivo

Ordenar os dois grupos esquerdo e direito, usando o mesmo método recursivamente Relativamente ao passo da divisão:

• Seja a Tabela v com n elementos. • Seja x o elemento pivot contido no meio da tabela (x = v[n/2]). Poderá ser introduzido o seguinte refinamento: • Inicializar i = 0 (índice da 1º posição da tabela). • Inicializar j = n-1 (índice da última posição da tabela). • Enquanto i ≤ j, fazer:

Enquanto v[i] < x (é sempre i≤ n-1), incrementar i Enquanto v[j] > x (é sempre j≥ 0), decrementar j Se i ≤ j, trocar v[i] com v[j], incrementar i e decrementar j

• O grupo esquerdo (com valores ≤ x) é v[0], ..., v[j] (vazio se j<0) • O grupo direito (com valores ≥ x) é v[i], ..., v[n-1] (vazio se i>n-1)

O tempo de execução é proporcional a

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 128

n * log n

onde n é o numero de elementos a serem ordenados. A ideia “de aceleração” por trás do algoritmo QuickSort é que é mais rápido ordenar duas sequências de n/2 elementos do que uma sequência de n elementos. Veremos em seguida um exemplo do passo da divisão.

Figura 51. Passo da divisão

O código da implementação do algoritmo é apresentado em seguida: public static void main(String[] args) { int tabela[] = new int[100]; Tabela.preenche(tabela); //preenche tabela Tabela.imprime(tabela); //imprime tabela antes da ordenação quickSort(tabela, 0, tabela.length-1); //ordena tabela Tabela.imprime(tabela); //imprime tabela depois de ordenada } static void quickSort (int tabela[], int pri, int ult) { int i = pri; int j = ult;

3 1 2 5 4 6 9 8 7

8 9 2 5 4 6 1 3 7

v: 8 9 2 5 4 6 1 3 7i j x=4

3 9 2 5 4 6 1 8 7

i j

3 1 2 5 4 6 9 8 7i j

3 1 2 4 5 6 9 8 7i j

< ≥ x ≤ x

(3.3)

(3.3)

(3.1+3.2) i j

(3.3)

i j (3.1+3.2)

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 129

int pivot = tabela[(pri + ult)/2]; do { while (tabela[i] < pivot) i++; while (tabela[j] > pivot) j--; if (i<= j) Tabela.troca(tabela,i++,j--); }while(i <= j); if (pri < j) quickSort(tabela, pri, j); if (i < ult) quickSort(tabela, i, ult); } }

8.6 - Exercícios práticos

Exerc.1 - Implemente um método que receba como parâmetro uma tabela de inteiros e retorne a tabela ordenada usando o algoritmo Bubble Sort Exerc.2 - Implemente um método que receba como parâmetro uma tabela de inteiros e retorne uma outra tabela ordenada. Use o algoritmo Selection Sort. Exerc.3 - Faça um método que receba como parâmetro uma tabela de objectos do tipo funcionário (nome e número fiscal) e retorne uma tabela ordenada. Use o algoritmo Shell Sort Exerc.4 - Implemente um programa que dado uma tabela de caracteres a ordene o algoritmo Selection Sort. Exerc.5 - Implemente um programa que:

1. receba o registo de automóveis (Marca e n.º registo) 2. guarde estes registos numa tabela 3. Ordene a tabela por marca, segundo o método quick Sort. 4. Apresente em seguida o resultado no ecran.

Exerc.6 - Uma loja pretende dispor os seus artigos de vestuário segundo cores. Para isso precisa de fazer uma pequena alteração à aplicação de suporte à gestão da loja, de modo a acrescentar a funcionalidade de listagem de artigos por ordem de cor, sendo a ordem de cores desejada (amarelo, laranja, castanho, beje, verde, azul, vermelho, cinzento e preto). Implemente o método que permite reordenar a tabela de objectos ArtigoVestuario segundo a ordem de cores desejada

public class ArtigoVestuario { public int cod; public String artigo, cor; …

}

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 130

9 - Recursividade

9.1 - Definições

A repetição de execução de um grupo de instruções para diferentes valores de dados pode ser implementada de duas formas:

• Iterativa (ou explícita). • Recursiva (ou implícita). Quando um método está definido em termos dele próprio.

Por exemplo, vejamos o cálculo do factorial de um número natural. Este pode ser feito de duas formas:

• Forma iterativa n! = n*(n-1)*(n-2)*…*1

• Forma recursiva (definindo-se uma forma recursiva da função)

1!=1 n! = n*(n-1)!

Um método recursivo é um método que directa ou indirectamente faz uma chamada a si mesmo (recorre a si próprio para resolver o problema). Como um método F resolve um problema chamando a si mesmo? O F chama a si em diferentes instâncias, com os valores diferentes. Exemplos:

• Examinar todos os arquivos de um directório D, incluindo todos os sub-directórios; • Procurar o significado de uma palavra num dicionário; • Definição de uma expressão aritmética numa linguagem de programação.

O uso da recursão é útil na resolução de problemas que podem ser decompostos em subprogramas mais simples e onde a solução final obtém-se pela composição das soluções desses subproblemas. Um método recursivo é definido em termos de uma instância menor de si mesmo. Devem existir duas condições fundamentais para implementar a recursividade:

• Um caso elementar (ou critério de paragem). No mínimo, sempre tem que haver um caso que pode ser resolvido sem recursividade. No exemplo do cálculo do factorial este critério é dado por 1!=1.

• O caso geral, ou parte recursiva. Qualquer chamada recursiva tem que progredir em direcção ao caso

elementar. No exemplo do cálculo do factorial este caso é n!=n*(n-1)!

A recursividade é muito usada, por exemplo, no cálculo de problemas matemáticos, contudo a recursividade pode causar problemas de memória em virtude da duplicação de variáveis locais, incluindo os parâmetros. Também devemos ter cuidado para não criar uma lógica circular que resulte em laços infinitos. Recursividade é uma poderosa ferramenta de programação que pode levar a algoritmos pequenos e eficientes. Recursividade, sempre leva a um código mais compacto. Exemplos: No exemplo seguinte será apresentado o cálculo do factorial de um número natural através da forma iteractiva e recursiva.

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 131

Iterativa public class FacInt { public static void main(String[] args) { for (int i = 0; i < 9; i++) System.out.println("f(" + i + ") = " + factorial(i)); } static long factorial(int n) { long f = 1; while (n > 1) f *= n--; return f; } } /* Output: f(0) = 1 f(1) = 1 f(2) = 2 f(3) = 6 f(4) = 24 f(5) = 120 f(6) = 720 f(7) = 5040 f(8) = 40320 */ Recursiva public class TestFactorialRec { public static void main(String[] args) { for (int i = 0; i < 9; i++) System.out.println("f(" + i + ") = " + fact(i)); } static long fact(int n) { if (n < 2) return 1; return n*fact(n-1); } } /*

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 132

Output: f(0) = 1 f(1) = 1 f(2) = 2 f(3) = 6 f(4) = 24 f(5) = 120 f(6) = 720 f(7) = 5040 f(8) = 40320 */ Veja-se para este último caso o rasto do cálculo do factorial f(3) = 3 * f(2) = 6 | 2 * f(1) = 2 | 1 * 1 = 1 Para finalizar, repare-se que:

• Numa implementação iterativa o ciclo está presente explicitamente como estrutura de repetição. • Numa implementação recursiva o ciclo está presente, mas mascarado por uma estrutura de selecção.

9.2 - Exercícios práticos

Exerc.1 – Escreva um algoritmo recursivo e respectivo método, que permita obter o resultado de A*B sendo A e B inteiros não negativos.

Nota: a*b = a if b=1 a*b =a*(b-1)+a

Exerc.2 – Escreva um algoritmo recursivo e respectivo método, que permita obter o resultado de A+B sendo A e B inteiros não negativos.

Nota: a+b = a if b=0 a+b =(a+1) + (b-1)

Exerc.3 – A sequência de Fibonacci é definida como: 1, 1, 2, 3, 5, 8, 13, 21, 34, ... Em que cada elemento desta sequência é a soma dos dois elementos precedentes:

Nota: Se n <= 2 então Fib(n) := 1; Se n > 2 então Fib(n) : = Fib(n-2)+ Fib(n-1);

Em que Fib(n) retorna o n-ésimo termo da sequência. Faça um programa que calcule o número da sequência de Fibonacci:

Iterativamente Recursivamente

Exerc.4 - Faça um método recursivo que calcule o valor de S, onde S = 1 + ½ + 1/3 + ¼ + 1/5 + 1/N. Exerc.5 - Escreva um método recursivo que calcula e retorna o valor de S(n), onde

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 133

S = 1 + 1/1! + ½! + 1/3! + 1 /N!. Exerc.6 - Escreva um método recursivo que calcula e retorna o valor de S(n), onde

S = 2/4 + 5/5 + 10/6 + 17/7 + 26/8 + ... +(n*2+1)/(n+3) Exerc.7 - Escreva um método recursivo que calcula e retorna a função potência Xⁿ. Exerc.8 - Faça um método recursivo que recebe um inteiro e retorna o seu número de dígitos. Exerc.9 – Escreva um método para calcular o valor da função de Ackmann, dada pela seguinte relação:

Nota: 1 se m = 0 A(m,n) = A(m-1,1) se m>0 e n=0 A(m-1,A(m,n-1)) se m>0 e n>0

Exerc.10 – Escreva um programa contendo o seguinte método recursivo que retorna o n-ésimo número Catalão: static long c( int n)

A sequência dos números Catalão é dada por : 1 1 2 5 14 42 132 429 ...

Em termos matemáticos a sua relação é dada por :

∑−

=

−+−++−+−=−−=1

0)0(.)1()1().2(....)2().1()1(.)0()1(.)()(

n

icnccncnccnccincicnc

Para efeitos comprovativos, em seguida, utilize a seguinte expressão e compare os resultados da sequência obtida:

)!1(.!)!2()(+

=nnnnc

Exerc.11 - Faça um método recursivo que ordene por ordem crescente os n elementos de um vector de inteiros de n posições. Exerc.12 - Faça uma função recursiva que calcule o mdc entre dois números:

mdc(n1,n2) = n1 , se n2 = 0 mdc(n1,n2) = mdc( n2, n1 mod n2), se n2 != 0

Exerc.13 - Dada a função X definida abaixo: Algoritmo X(n,m: inteiro): inteiro; inicio se (n=m) ou (m=0) entao X = 1 senao X = X(n-1,m) + X(n-1,m-1) fim Qual o valor de X(5,3) ? Quantas chamadas serão feitas na avaliação acima ?

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 134

10 - Anexo I – Exemplo Introdutório em Java

Neste anexo apresenta-se a título de exemplo introdutório ao Java a classe Aluno que foi teoricamente explicada no capitulo 2. public class Aluno { //ATRIBUTOS private String nome; private int numero; private int ano; private String curso; private char turma; private double valorPropina; private double valorPago; //CONSTRUTORES public Aluno(String nom, int num, String curs, int an, char turm) { nome = nom; numero =num; ano=an; curso=curs; turma=turm; valorPropina=0; valorPago=0; } // metodos selectores public int getNumero() { return numero; } public String getNome() { return nome; } public String getCurso() { return curso; } public int getAno() { return ano; } public char getTurma() { return turma; }

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 135

public double getPropina() { return valorPropina; } public double getValorPago() { return valorPago; } // metodos modificadores public void setCurso(String curs) { curso=curs; } public int setAno() { return ano; } public void setTurma(char turm) { turma=turm; } public void setPropina(double valor) { valorPropina=valor; } // outros métodos public String toString() { String str= "Nome:" + nome + "Numero :" + numero + " curso : " + curso + " ano" + ano; return str; }; // metodo que calcula valor da propina ja pago public void pagarPropina(double valor) { valorPago=valorPago+valor; } // metodo que calcula a divida public double calculaDivida() { return valorPropina-valorPago; } // metodo que verifica se a propina já foi paga public boolean verificaPropinaPaga() { boolean resultado=calculaDivida()==0; return resultado; } }

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 136

11 - Anexo II – Glossário

Nota: Os significados apresentados para as palavras colocadas neste glossário são apenas os que se consideraram necessários no âmbito da cadeira de Introdução à Programação. As palavras encontram-se descritas por ordem alfabética. Abordagem: conjunto de acções tomadas para definir a forma de atingir a solução de um determinado problema. Algoritmo: Conjunto de instruções que resolvem um problema. Ambiguidade: Expressão cujo significado não pode ser determinado a partir do contexto em que está inserida (ou seja, que a partir de determinado ponto oferece mais do que um caminho a seguir, podendo levar a resultados diferentes). Bottom-Up: Construção de uma solução partindo dos elementos mais pequenos. Código fonte: Código escrito pelo programador. Código executável: Resultado da compilação do código fonte. Conceber: Criar. Compilador: Programa que sabe interpretar o código escrito numa determinada linguagem de programação. Recebe código fonte como elemento de entrada e produz código executável. Compilação: Processo de gerar código executável a partir de código fonte recorrendo a um compilador. Divide-And-Conquer: Metodologia ou forma de resolução de problemas que envolve partir um problema em subproblemas mais pequenos, cujas soluções combinadas representam a solução do problema original. Estado: Situação em que se encontra uma variável em termos de valor actual. O estado de um objecto é o conjunto de valores dos seus atributos. No que diz respeito a um problema, tem um estado inicial que corresponde ao valor do resultado que ainda não existe, e um estado final que é o valor de resultado após passar pela fase de transformação. Hardware: Componentes físicos de um computador (discos, monitores, colunas, etc.) Implementação: Código produzido por um programador e que representa uma solução possível para um determinado problema. Linguagem de Programação: Linguagem artificial utilizada para levar a cabo a implementação de programas de computador. Máquina Virtual: Na prática é um computador simulado dentro do próprio computador através de software próprio criado para esse efeito. Comporta-se como se fosse um computador independente. A máquina virtual Java actua como um ambiente de execução de programas Java auto-contido. Notação: Mecanismo que serve para definir o formato de determinado tipo de informação. Por exemplo: a BNF serve para definir gramáticas para variados tipos de linguagens, tal como o XML serve para definir formato de dados, os símbolos musicais servem para definir músicas nas partituras, etc, etc.

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 137

Operandos: elementos envolvidos numa determinada operação. Quotidiano: algo relativo ao dia-a-dia. Pseudocódigo: forma simplificada de descrever um algoritmo recorrendo a palavras chave semelhantes às da linguagem natural, mas que são estruturadas à semelhança de um programa de computador. Sistema de Numeração: Esquema de representação de magnitudes ou quantidades através de um grupo de dígitos. Basicamente, é uma notação de representação de números. Sistema Operativo: Programa de computador de grandes dimensões e complexidade que é responsável não só por esconder os detalhes do hardware aos utilizadores e programadores, como também tem de gerir a memória disponível para cada aplicação(programa em execução, também chamado de processo) e gerir a execução dessas mesmas aplicações, gerir o sistema de comunicação com outras máquinas, etc. Software: Programa de computador. Representa a parte lógica, ao contrário do hardware que representa a parte física de um computador. Subprograma: Também chamados de rotinas (ou métodos no caso de linguagens orientadas a objectos como é o caso do Java), são pequenos programas que podem ser chamados e chamar outros programas para que em conjunto colaborem na obtenção de uma solução para determinado problema. Top-Down: Cosntrução de uma solução em que a partir do problema maior se tenta ir descendo de nível e especificando a cada passo os níveis intermédios, ou seja, os problemas mais pequenos.

Sebenta da Disciplina de Introdução à Programação

© Escola Superior de Tecnologia de Setúbal 2005-2006 Página 138

12 - Anexo III - Bibliografia

Fundamentos de Programação em Java2 – António Mendes, Maria José Marcelino, FCA Java Software Solutions, John Lewis, Addison Wesley Programação em Java2 – Pedro Coelho, FCA Introdução à Programação Utilizando Pascal, Pavão Martins, McGraw-Hill The Java Programming Language – Ken Arnold, James Gosling . Addison Wesley Acetatos de IP dos anos lectivos 2000/2001 até 2003/2004