DET 111 – Programação de Computadores II Semestre 2012/II FACULDADE DE VIÇOSA Bacharelado em Sistemas de Informação DET111 [Programação de Computadores II] Semestre 2012/II DET 111 – Programação de Computadores II Semestre 2012/II Índice 1.CONCEITOS BÁSICOS 2.CLASSE E APLICAÇÃO 3.SINTAXE BÁSICA 4.CONSTRUTORES E SOBRECARGA 4.1CONSTRUTORES 4.2SOBRECARGA DE MÉTODOS 5.CAMPOS E MÉTODOS ESTÁTICOS 6.ESTRUTURAS DE DECISÃO E CONTROLE CONDICIONAIS 7.EXERCÍCIOS 8.REUTILIZAÇÃO DE CLASSES 9.ARRAYS EM JAVA 10.CLASSES PARA MANIPULAÇÃO DE STRINGS 10.1A CLASSE STRING 10.1.1CONSTRUINDO INSTÂNCIAS 10.1.2MÉTODOS BÁSICOS DA CLASSE STRING 10.2A CLASSE STRINGBUFFER 10.3A CLASSE STRINGTOKENIZER 1 7 10 26 27 28 30 34 37 39 47 54 54 55 55 57 57 DET 111 – Programação de Computadores II Semestre 2012/II 1. Conceitos Básicos 1.1 Introdução História do Java A revolução dos microprocessadores tornou possível o desenvolvimento de computadores pessoais que modificaram profundamente a vida das pessoas e a forma que as organizações conduzem e gerenciam seus negócios. Os microprocessadores são utilizados em dispositivos inteligentes eletrônicos voltados para o consumidor. Reconhecendo isto, a Sun, em 1991, financiou um projeto de pesquisa corporativa interna com o codinome Green, que resultou no desenvolvimento de uma linguagem baseada em C++ que seu criador, James Gosling, chamou Oak em homenagem a uma árvore de carvalho vista por sua janela na Sun. Descobriu-se mais tarde que já havia uma outra linguagem com o mesmo nome. Quando uma equipe da Sun visitou uma cafeteria local, o nome Java (cidade de origem de um tipo de café) foi sugerido; e o nome pegou. O projeto Green passava por algumas dificuldades. O mercado de dispositivos eletrônicos inteligentes voltados para o consumidor popular não estava se desenvolvendo, no início da década de 1990, tão rápido como a Sun havia antecipado. O projeto corria o risco de ser cancelado. Por uma feliz casualidade, a World Wide Web explodiu em popularidade em 1993 e a equipe da Sun viu o imediato potencial de utilizar Java para adicionar conteúdo dinâmico, como interatividade e animações, às páginas da Web. Isso deu nova vida ao projeto. A Sun anunciou o Java formalmente em uma importante conferência em maio de 1995. O Java chamou a atenção da comunidade de negócios por causa do interessa na www. O Java é agora utilizado para desenvolver aplicativos corporativos de grande porte, aprimorar a funcionalidade de servidores Web, fornecer aplicativos para dispositivos voltados para o consumo popular e para muitos outros propósitos. Classes e Bibliotecas Programas Java consistem em partes chamadas classes. As classes incluem métodos que realizam tarefas e retornam informações ao concluir, incluem também construtores e campos. Os programadores desenvolvem cada parte de que precisam para formar programas Java. Entretanto, a maioria dos programadores Java tira proveito das coleções de classes existentes nas bibliotecas de classes Java, que também são conhecidas como APIs (Application Programming Interfaces). Portanto, existem dois aspectos para aprender: a própria linguagem Java, de modo que você possa programar suas próprias classes, e as classes nas extensas bibliotecas de classe Java. Ambiente de desenvolvimento Java típico Os programas Java, em geral passam por cinco fases – edição, compilação, carga, verificação e execução. As figuras a seguir ilustram estas fases. Pág.: 1 DET 111 – Programação de Computadores II Semestre 2012/II Edição O programa é criado em um editor e armazenado no disco em um arquivo com a extensão .java. Para organizações que desenvolvem sistemas de informações substanciais, ambientes de desenvolvimento integrado (IDEs – Integrated Development Environment) estão disponíveis a partir de vários fornecedores de software importantes. Os IDEs cotam com ferramentas que suportam o processo de desenvolvimento, incluindo editores e depuradores. A figura 1 apresenta um esquema da fase de edição. class ContaBancaria { private String nome; private float saldo; EDITOR ContaBancaria() { } DISCO public void deposita(float v) { saldo = saldo + v; } } Figura 1 Fase de Edição Entre os vários IDEs populares destacam-se o Eclipse (www.eclipse.org), o NetBeans (www.netbeans.org) e o BlueJ (www.bluej.org). A Figura 2 mostra a tela inicial do BlueJ. Um ambiente de desenvolvimento criado especialmente para cursos introdutórios de Java, totalmente orientado a objetos. Este possui recursos para facilitar o entendimento da relação entre os elementos do paradigma de orientação por objetos. Observe a apresentação da classe (ContaBancariaSimplificada), do objeto conta1, disponibilizado na bancada de objetos, na parte inferior da tela e a inspeção do objeto criado pelo Object Inspector. BlueJ suporta − − − − − − − − − Ambiente totalmente integrado; Exibição gráfica das classes do projeto; Edição textual e gráfica; Possui editor, compilador, máquina virtual, depurador, etc; Interface fácil de utilizar, ideal para iniciantes; Criação de objetos de forma interativa; Chamadas de procedimentos de forma interativa; Realizar testes de forma interativa; Desenvolvimento de aplicações de forma incremental. Pág.: 2 DET 111 – Programação de Computadores II Semestre 2012/II Figura 2 Uma tela do Bluej Outro ambiente para desenvolvimento de sistemas em Java é o Eclipse. Eclipse é mais que uma ambiente de desenvolvimento, é uma comunidade de código aberto, cujos projetos são focados no desenvolvimento de plataformas extensíveis, ferramentas e ambientes de runtime para construir, desdobrar e gerenciar o software durante seu ciclo de vida. O projeto Eclipse foi originalmente criado pela IBM em novembro de 2001 e suportado por um consórcio de vendedores de software. A Eclipse Foundation foi criada em 2004 como uma corporação independente, sem fins lucrativos, para agir como o “gerente” da comunidade de Eclipse. A corporação sem fins lucrativos e independente foi criada para permitir vendedores neutros e expandir uma comunidade transparente ao redor de Eclipse. Hoje, a comunidade de Eclipse consiste em indivíduos e organizações da indústria de software. A Figura 3 apresenta uma tela do ambiente de desenvolvimento Eclipse. A princípio utilizaremos o ambiente BlueJ e depois passaremos para o Eclipse. Pág.: 3 DET 111 – Programação de Computadores II Semestre 2012/II Figura 3 Tela do Eclipse Temos acima o código fonte da classe AppContaBancaria, a saída em console resultante da chamada do método que exibe as informações armazenadas no objeto. Compilação O compilador cria bytecodes e os armazena no disco em um arquivo com extensão .class. Para compilar um programa chamado ContaBancaria.java, você digitaria: javac ContaBancaria.java Os bytecodes são executados pela Java Virtual Machine (JVM). A máquina virtual (Virtual Machine – VM) é um aplicativo de software que simula um computador, mas oculta o sistema operacional e o hardware subjacentes dos programas que interagem com a VM. Se a mesma VM for implementada nas várias plataformas de computador, os aplicativos que ela executa podem ser utilizados em toas essas plataformas. Ao contrário da linguagem de máquina, que é dependente de hardware específico, os bytecodes são instruções independentes de plataforma, são portáveis. Para executar o aplicativo Java do nosso exemplo, após a geração do arquivo .class, digitaríamos: Pág.: 4 DET 111 – Programação de Computadores II Semestre 2012/II java ContaBancaria A Figura 4 ilustra o processo de compilação. BYTECODES COMPILADOR class ContaBancaria { private String nome; private float saldo; ContaBancaria() { } public void deposita(float v) { saldo = saldo + v; } BIBLIOTECAS } 01110001100101110110101111101100 00110010111011010111110110011101 01110001100101110110101111101100 00110010111011010111110110011101 01110001100101110110101111101100 00110010111011010111110110011101 01110001100101110110101111101100 00110010111011010111110110011101 01110001100101110110101111101100 00110010111011010111110110011101 01110001100101110110101111101100 00110010111011010111110110011101 01110001100101110110101111101100 00110010111011010111110110011101 01110001100101110110101111101100 00110010111011010111110110011101 01110001100101110110101111101100 00110010111011010111110110011101 DISCO javac <nomeDoArquivo>.java Figura 4 A fase de Compilação Carregamento e Verificação O carregador de classe transfere os arquivos contendo os bytecodes do programa para a memória principal. O carregador de classe também carrega qualquer arquivo .class fornecido pelo Java que seu programa utiliza. Enquanto as classes são carregadas, o verificador de bytecodes examina seus bytecodes para assegurar que eles são válidos e não violam restrições de segurança em Java. O Java impõe forte segurança para certificar-se de que os programas Java que chegam pela rede não danifiquem os arquivos ou sistemas. O esquema do carregamento e verificação é mostrado na Figura 5. Execução A JVM executa os bytecodes do programa, realizando assim as ações especificadas pelo programa. Nas primeiras versões do Java, a JVM era simplesmente um interpretador para bytecodes Java. Isso fazia com que a maioria dos programas Java executasse lentamente porque a JVM interpretava e executava um bytecode por vez. Em geral, as JVMs atuais executam bytecodes utilizando uma combinação de interpretação e a chamada compilação just-in-time (JIT). Nesse processo, a JVM analisa os bytecodes à medida que são interpretados, procurando hot spots (pontos ativos) – partes dos bytecodes que executam com frequência. Para essas partes, um compilador JIT – conhecido como compilador Java HotSpot – traduz os bytecodes para a linguagem de máquina do computador subjacente. Quando a JVM encontra novamente essas partes compiladas, o código da linguagem de máquina mais rápido é executado. Pág.: 5 java <nomeDoArquivo> DET 111 – Programação de Computadores II Semestre 2012/II JVM 01110001100101110110101111101100 00110010111011010111110110011101 01110001100101110110101111101100 00110010111011010111110110011101 01110001100101110110101111101100 00110010111011010111110110011101 01110001100101110110101111101100 00110010111011010111110110011101 01110001100101110110101111101100 00110010111011010111110110011101 01110001100101110110101111101100 00110010111011010111110110011101 01110001100101110110101111101100 00110010111011010111110110011101 01110001100101110110101111101100 00110010111011010111110110011101 01110001100101110110101111101100 00110010111011010111110110011101 CARREGADOR VERIFICADOR BIBLIOTECAS ... MEMÓRIA DISCO Figura 5 Carregamento e Verificação Portanto, os programas Java passam por duas fases de compilação – uma em que o código-fonte é traduzido em bytecodes (para a portabilidade) e uma segunda em que, durante a execução, os bytecodes são traduzidos em linguagem de máquina para o computador real em que o programa é executado. A Figura 6 ilustra o processo de execução. INTERPRETADOR COMPILADOR JIT ... Figura 6 Processo de Execução MEMÓRIA Pág.: 6 DET 111 – Programação de Computadores II Semestre 2012/II 2. Classe e Aplicação Considere a classe abaixo: ContaBancariaSimplificada - nomeDoCorrentista: String - saldo: float - contaÉEspecial: Boolean + ContaBancariaSimplificada() // “zera” todos os campos + setNomeDoCorrentista(pNome: String) + setContaEspecial(pContaEspecial: boolean) + deposita(valor: float) + retira(valor: float) + mostraDados() Algumas • • • questões: Qual o nome da classe? Quais são os campos desta classe? Quais são os métodos que os objetos desta classe podem executar? • Por que existem elementos com o sinal – e outros com o sinal +? O código desta classe em Java é mostrado abaixo. Digite-a no BlueJ e solicite para ver a documentação da classe gerado pelo javadoc, ferramenta que gera a documentação baseada nos comentários e controles inseridos nos comentários como @autor, @version, @param e @return. /** * A classe ContaBancariaSimplificada permite manipular conta correntes simplificada, * fazendo saldos e saques. * @author Maria Vanderléa de Queiroz * @version 1 - 02/08/06 */ public class ContaBancariaSimplificada { // campos ou variáveis de instâncias private String nomeDoCorrentista; private float saldo; private boolean contaÉEspecial; private char sexo; /** * Constrói objetos da classe ContaBancariaSimplificada */ public ContaBancariaSimplificada() { // inicializa campos da classe nomeDoCorrentista = ""; saldo = 0; contaÉEspecial = false; sexo = ' '; } /** * Atualiza o nome do correntista * @param pNome Recebe o valor passado para o campo nome * */ public void setNomeDoCorrentista(String pNome) { nomeDoCorrentista = pNome; } Pág.: 7 DET 111 – Programação de Computadores II Semestre 2012/II /** * Retorna o nome do correntista */ public String getNome() { return nomeDoCorrentista; } /** * Altera o status da conta */ public void setContaÉEspecial(boolean pContaEspecial) { contaÉEspecial = pContaEspecial; } /** * Retorna true se a conta é do tipo especial e false caso contrário */ public boolean getContaEspecial() { return contaÉEspecial; } public void setSexo(char s) { sexo = s; } /** * Retorna o sexo do correntista */ public char getSexo() { return sexo; } /** * Acrescenta ao campo saldo o valor do depósito passado como parâmetro */ public void deposita(float valor) { saldo = saldo + valor; } /** * Retira do campo saldo o valor passado como parâmetro */ public void retira(float valor) { if (saldo > valor ) saldo = saldo - valor; else System.out.println("Saldo insuficiente"); } /** * Retorna o saldo da conta */ public float getSaldo() { return saldo; } /** * Exibe no console os dados da conta */ public void mostraDados () { System.out.println("Nome do correntista: "+getNome()); System.out.println("Saldo: "+getSaldo()); if (contaÉEspecial) System.out.println("Tipo: ESPECIAL"); Pág.: 8 DET 111 – Programação de Computadores II Semestre 2012/II else System.out.println("Tipo: CONTA COMUM"); if (sexo == 'F') System.out.println("Correntista do sexo feminino"); else System.out.println("Correntista do sexo masculino"); } } Após a digitação solicite a compilação da classe. Corrija os erros caso ocorram e ao finalizar a compilação com sucesso vá tela inicial onde é mostrada a classe e solicite a criação de uma nova instância da classe com o nome conta1. Coloque nele dados inventados por você e faça depósitos, retiradas e solicite a exibição das informações para testar. Aplicação Java Uma aplicação Java é uma classe que possui o ponto inicial de execução, representado pelo método main. Este método possui uma assinatura própria que pode ser observada no código abaixo. Estudaremos sobre métodos estáticos mais a frente, mas para adiantar, um método estático é aquele que não precisa de uma instância para ser chamado. Os colchetes abrindo e fechando significa que o parâmetro denominado, neste exemplo, de argumentos é um array com objetos da classe String. Esta aplicação instancia um objeto chamado conta1 do tipo ContaBancaria e solicita que ele execute várias ações (métodos). /** * Esta classe testa a classe ContaBancariaSimplificada * * @author Maria Vanderléa de Queiroz * @version 1.0 */ public class AppContaBancaria { /** * O método main é o ponto onde se inicia a execução do aplicativo. */ } public static void main (String argumentos[]) { ContaBancariaSimplificada conta1 = new ContaBancariaSimplificada(); conta1.setNomeDoCorrentista("Carla Soares"); conta1.setSexo('M'); conta1.deposita(950); conta1.retira(100); conta1.mostraDados(); } Pág.: 9 DET 111 – Programação de Computadores II Semestre 2012/II 3. Sintaxe Básica Regras básicas de sintaxe Uma classe em Java é sempre declarada com a palavra-chave class seguida do nome da classe. • O nome da classe não pode conter espaços • Deve sempre ser iniciado por uma letra • Para nome de classes, métodos e campos em Java, o caractere sublinhado e o símbolo $ são considerados letras • O nome da classe não deve conter acentos e pode conter números, contando que apareçam depois de uma letra Nomes de classes não podem ser exatamente iguais às palavras reservadas de Java Existe diferenciação entre caractere maiúsculo e minúsculo O conteúdo da classe é delimitado por {}. A cada caractere { deve haver um correspondente } Não existem regras especiais para indentação horizontal, porém espaçamento adequado e indentação regular fazem com que o código fique mais claro e fácil de ler Tradicionalmente os nomes das classes começam com caracteres maiúsculos e alternam entre letras Existem três tipos de comentários em Java, que serão ignorados pelo compilador: • Comentários de uma única linha que iniciam a linha // e terminam ao final da linha • Comentários em bloco são delimitados pelos caracteres /* no início e */ no fim • Comentários em bloco para documentação são similares aos comentários em bloco comuns, exceto que são iniciados pela seqüência /** em vez de /*. Estes comentários podem ser analisados pela ferramenta javadoc para criação automática de documentação da classe. É aconselhável que os arquivos criados em editores de texto contenham somente uma classe, e que os nomes dos arquivos sejam compostos do nome da classe seguida da extensão .java. Campos de classes em Java Campos em Java são declarados dentro do corpo da classe. Cada campo (que representa modelos do mundo real) deve ser representando por um tipo de dado que é característico da linguagem de programação utilizada. Dados nativos Existem poucos dados nativos em Java, isto é, dados que são parte da linguagem e não instâncias de outras classes. boolean: valores lógicos (true ou false) tipos numéricos o byte: ocupa um byte de memória e representa valores entre –128 e 127, inclusive o short: ocupa dois bytes de memória e representa valores entre –32768 e 32767, inclusive o int: ocupa quatro bytes e representa valores entre –2147483648 e 2147483647, inclusive o long: ocupa oito bytes e representa valores entre –9223372036854775808 e 9223372036854775807, inclusive char o também é um tipo numérico inteiro, mas é mais usado para representar caracteres Unicode entre 0 e 65535, inclusive o usa dois bytes de memória Pág.: 10 DET 111 – Programação de Computadores II Semestre 2012/II são representados entre aspas simples operações matemáticas básicas podem ser feitas com campos do tipo char como se fossem de outros tipos inteiros ponto flutuante o float: valores com precisão simples com valores entre 1.40129846432481707 e-45 e 3.4028246638528860 e+38, usando quatro bytes de memória o double: valores com precisão dupla com valores entre 4.94065645841246544e-324 e 1.79769313486231570e+308, usando oito bytes de memória o observação: os tipos numéricos em Java preservam suas características e limitações independentemente do sistema operacional ou arquitetura de computador String: é uma classe usada para representar cadeias de caracteres. Não são dados nativos (instâncias da classe String), mas como seu uso é intuitivo e simples, utilizaremos instâncias de String de forma similar aos dados nativos. Declaração de campos • Declara-se o tipo do campo seguido dos nomes dos campos que serão daquele tipo • Os nomes dos campos: o iniciam com uma letra (incluindo _ e $) o devem ser compostos de uma única palavra e podem ser compostos por letras e números o podem conter acentos o não podem ser iguais às palavras reservadas o tradicionalmente começam com caracteres minúsculos, alternando com letras maiúsculas entre palavras • podem conter modificadores de acesso (private, public, protected) o public: garante que o campo ou método da classe poderá ser acessado ou executado a partir de qualquer outra classe o private: só podem ser acessados, modificados ou executados por métodos da mesma classe, sendo completamente ocultos para o programador usuário que for usar instâncias desta classe ou criar classes herdeiras ou derivadas o protected: funciona como o private, exceto que classes herdeiras também terão acesso ao campo ou método marcado com este modificador o package ou friendly: sem modificador de acesso, significando que seus campos e métodos serão visíveis (acessados) para todas as classes de um mesmo pacote (package = grupo de classes que mantém uma relação entre si). • o campo que referência uma instância de uma classe é necessário criar uma referência com a palavra chave new, formato básico: NomeDaClasse nomeDaReferencia = new NomeDaClasse(); o o • • • • • Métodos em Java Nomes dos métodos seguem as mesmas regras de nomes de campos Refletem ações que são efetuadas nos campos da classe e/ou valores passados como argumentos para estes métodos Tradicionalmente os nomes dos métodos começam com caractere minúsculo e alternam maiúsculas entre caracteres Métodos não podem ser criados dentro de outros métodos, nem fora da classe à qual pertencem O formato genérico usado para declarações de métodos é modificador-de-acesso tipo-ou-classe-de-retorno nome-do-método(lista de argumentos) Pág.: 11 DET 111 – Programação de Computadores II Semestre 2012/II • • • • A declaração de métodos não é terminada com ponto e vírgula Cada método deve ter, na sua declaração, um tipo ou classe de retorno, correspondente ao valor que o método deve retornar. Caso nada retorne, o valor de retorno deverá ser void Métodos que retornem algum valor diferente de void devem ter, em seu corpo, a palavra-chave return seguida de uma constante ou variável do tipo ou da classe que foi declarada como sendo a de retorno do método Métodos podem ter listas de argumentos, ou seja, variáveis contendo valores que podem ser usados pelos métodos para efetuar suas operações Escopo O escopo dos campos e variáveis de uma classe determina a sua visibilidade (se podem ser acessadas ou modificadas em todos os métodos da classe, somente em determinado método ou mesmo somente em parte de um determinado método). • Campos são válidos por toda a classe • Variáveis e instâncias declaradas dentro de métodos só serão válidas dentro desses métodos • Dentro de métodos e blocos de comandos, a ordem de declaração de variáveis e referências a instâncias é considerada: variáveis dentro de métodos só podem ser usadas depois de declaradas • Parâmetros só são válidos dentro dos métodos < > <= >= == != && || ! Retorna true Retorna true Retorna true Retorna true Retorna true Retorna true E lógico OU lógico NÃO lógico se se se se se se o o o o o o valor valor valor valor valor valor à à à à à à Operadores esquerda for menor que o da direita esquerda for maior que o da direita esquerda for menor ou igual que o da direita esquerda for maior ou igual que o da direita esquerda for exatamente igual ao da direita esquerda for diferente ao da direita Criando aplicações em Java Classes não são programas de computador. Programas completos devem ser capazes de executar um algoritmo, ou seja, uma tarefa com passos definidos para a solução de um problema. O primeiro passo para a execução de um programa é chamado ponto de entrada. Os métodos das classes podem ser considerados algoritmos capazes de resolver problemas relacionados às classes a que pertencem, mas definitivamente não são soluções completas. Em Java podemos criar em uma classe um método especial que será considerado o ponto de entrada de um programa. A presença deste método na classe fará com que a classe se torne executável, e dentro desse método poderemos ter a criação e manipulação de ados e instâncias de classes. Este método especial em Java é chamado main. Este método terá ainda que ter os modificadores public static (nesta ordem), retornando void e receber como argumento um array de instâncias da classe String: public static void main(String [] argumentos) Em princípio o método main pode fazer parte de qualquer classe, porém vamos tentar fazer com que o método main, sempre que possível, seja o único método de uma classe. Exemplos Pág.: 12 DET 111 – Programação de Computadores II Semestre 2012/II public class Data { private byte dia,mês; private short ano; public void inicializaData(byte d, byte m, short a) { if (dataÉVálida(d,m,a)) { dia = d; mês = m; ano = a; } else { dia = 0; mês = 0; ano = 0; } } public byte getDia() { return dia; } public byte getMês() { return mês; } public short getAno() { return ano; } public boolean dataÉVálida(byte d, byte m, short a) { if ((d >= 1) && (d <= 31) && (m >= 1) && (m <= 12)) return true; else return false; } } public void mostraData() { System.out.println(dia+" / "+mês+" / "+ano); } public class DemoData { public static void main(String[] args) { Data hoje1, hoje2, ontem; Data natal2005 = new Data(); byte d, m; short a; d = 17; m = 8; a = 2006; hoje1 = new Data(); hoje1.inicializaData(d,m,a); hoje2 = hoje1; hoje.mostraData(); } natal2005.inicializaData((byte)25,(byte)12,(short)2005); natal2005.mostraData(); } Pág.: 13 DET 111 – Programação de Computadores II Semestre 2012/II A palavra-chave new dia 17 mês 8 ano 2006 hoje1 hoje2 dia 25 mês 12 ano 2005 natal2005 ? natal2005 As referências apontam para as instâncias. Mesmo que duas instâncias de uma classe contenham os mesmos dados encapsulados, elas não são iguais, afinal ocupam posições diferentes na memória. A referência ontem foi declarada mas não teve nenhuma instância associada. Qualquer tentativa de chamar algum método da classe Data através desta instância causará erro. Referências são independentes: se duas referências apontam para a mesma instância e a primeira é modificada para apontar para outra instância, a segunda referência continua apontando para a primeira instância. Observe esta outra versão da classe DemoData. import javax.swing.JOptionPane; public class DemoData { public static void main(String[] args) { Data hoje1, hoje2; Data natal2005 = new Data(); byte d, m; short a; d = Byte.parseByte(JOptionPane.showInputDialog("Entre com o dia")); m = Byte.parseByte(JOptionPane.showInputDialog("Entre com o mês")); a = Short.parseShort(JOptionPane.showInputDialog("Entre com o ano")); hoje1 = new Data(); hoje1.inicializaData(d,m,a); hoje2 = hoje1; natal2005.inicializaData((byte)25,(byte)12,(short)2005); hoje1.mostraData(); hoje2.mostraData(); natal2005.mostraData(); } } Pág.: 14 DET 111 – Programação de Computadores II Semestre 2012/II Exercício Proposto Desenvolva a seguinte classe em Java usando o BlueJ: Eq2Grau - coeficienteA: float - coeficienteB: float - coeficienteC: float + Eq2Grau() + Eq2Grau(a,b,c: float) + setA(n: float) + setB(n: float) + setC(n: float) + getA(): float + getB(): float + getC(): float - getDelta(): float + getRaizes() String Em seguida crie uma aplicação (DemoEq2Grau) para fazer a interação com o usuário através da classe JOptionPane (do pacote javax.swing.JOptionPane) para receber os dados e exibir os resultados: • JOptionPane.showInputDialog é um método que permite criar uma janela de diálogo para entrada de dados, retornando uma String. • JOptionPane.showMessageDialog é um método que permite exibir uma janela de diálogo. Exemplos: String string1 = JOptionPane.showInputDialog(“Entre com seu nome”); JOptionPane.showMessageDialog(null,”Seu nome é “+string1,”Caixa de saída”,JOptionPane.PLAIN_MESSAGE); Argumentos do método estático showMessageDialog: • O primeiro argumento ajuda o aplicativo Java a determinar onde posicionar a caixa de diálogo. O valor null indica que o diálogo deve aparecer no centro da tela do computador (podemos especificar que a caixa apareça no centro de uma janela particular, basta colocar seu nome). • O segundo argumento é a mensagem a ser exibida. • O terceiro argumento é a string da barra de títulos. • O quarto argumento define o tipo do diálogo exibido: Tipo de diálogo de mensagem ERROR_MESSAGE Ícone Descrição Indica um erro para o usuário INFORMATION_MESSAGE Indica informação WARNING_MESSAGE Indica um problema em potencial Diálogo que impõe uma pergunta ao usuário. Normalmente exige uma resposta, como clicar em um botão Yes ou No. Contém uma mensagem apenas. QUESTION_MESSAGE PLAIN_MESSAGE Sem ícone Segue abaixo o código da classe Eq2Grau. Pág.: 15 DET 111 – Programação de Computadores II Semestre 2012/II Após digitar o código e compilá-lo solicite a visualização da interface (documentação) da classe, no BlueJ selecione-a no canto superior esquerdo como mostrado na figura abaixo: Pág.: 16 DET 111 – Programação de Computadores II Semestre 2012/II Exercício resolvido /** * Os objetos criados a partir desta classe podem calcular e exibir * as raízes de uma equação do 2º grau * @author (Maria Vanderléa de Queiroz) * @version (v 1.0 de 25/08/2006) */ public class Eq2Grau { private double cA; private double cB; private double cC; /** * Constrói o objeto zerando seus campos */ public Eq2Grau() { cA = 0; cB = 0; cC = 0; } /** * Constrói o objeto atribuindo os valores dos campos * @param a,b,c double - parâmetros que correspondem aos coeficientes */ public Eq2Grau(double a, double b, double c) { cA = a; cB = b; cC = c; } /** * Atualiza o valor do campo cA * @param n um parâmetro do tipo double * @return void */ public void setA(double n) { cA = n; } /** * Atualiza o valor do campo cB * @param n um parâmetro do tipo double * @return void */ public void setB(double n) { cB = n; } /** * Atualiza o valor do campo cC * @param n um parâmetro do tipo double * @return void */ public void setC(double n) { cC = n; } Pág.: 17 DET 111 – Programação de Computadores II Semestre 2012/II /** * Retorna o coeficiente A * * @param * @return o valor do coeficiente A */ public double getA() { return cA; } /** * Retorna o coeficiente B * @param * @return o valor do coeficiente B */ public double getB() { return cB; } /** * Retorna o coeficiente C * @param * @return o valor do coeficiente C */ public double getC() { return cC; } /** * Retorna o valor de delta * @param * @return o valor de delta calculado por b*b - 4*a*c */ private double calculaDelta() { return (cB*cB)-(4*cA*cC); } /** * Retorna uma string contendo as raízes da equação ou uma * mensagem informando que não existem raízes reais * @param * @return string informando o resultado */ public String calculaRaizes() { double delta = calculaDelta(); if (delta < 0) return "Não existem raízes"; else { double x1 = (-cB + Math.sqrt(delta))/(2*cA); double x2 = (-cB - Math.sqrt(delta))/(2*cA); return "x1 = "+x1+" x2 = "+x2; } } } Segue abaixo a classe de demonstração que cria um objeto da classe Eq2Grau que contém o método , recebe do teclado seus coeficientes e exibe o resultado. Pág.: 18 DET 111 – Programação de Computadores II Semestre 2012/II import javax.swing.JOptionPane; /** * Esta classe demonstra o funcionamento da classe Eq2Grau * * @author (Maria Vanderléa de Queiroz) * @version (1.0 de 25/08/2006) */ public class DemoEq2Grau { public static void main(String[] argumentos) { double a = Double.parseDouble(JOptionPane.showInputDialog("A: ")); double b = Double.parseDouble(JOptionPane.showInputDialog("B: ")); double c = Double.parseDouble(JOptionPane.showInputDialog("C: ")); Eq2Grau eq = new Eq2Grau(a,b,c); JOptionPane.showMessageDialog(null,eq.calculaRaizes(),"Resultado",JOptionPane.PLAIN_MESSA GE); } } Exercício Proposto Observe a classe abaixo: /** * The Student class represents a student in a student administration system. * It holds the student details relevant in our context. * * @author Michael Kolling and David Barnes * @version 2006.03.30 */ public class Student { // o nome completo do estudante private String nome; // identificação (ID) do estudante private String id; // a quantidade de créditos do estudante private int creditos; /** * Cria um novo estudante com um determinado nome e ID with a given name and ID number. */ public Student(String nomeCompleto, String idEstudante) { nome = nomeCompleto; id = idEstudante; creditos = 0; } /** * Retorna o nome completo do estudante */ public String getNome() { return nome; } /** * Atribui um novo nome para o estudante */ public void trocaNome(String novoNome) nome = novoNome; { Pág.: 19 DET 111 – Programação de Computadores II Semestre 2012/II } /** * Retorna o ID do estudantee */ public String getID() { return id; } /** * Adicionar créditos para o estudante */ public void adicionaCreditos(int n) { creditos += n; } /** * Retorna o número de créditos que o estudante acumulou */ public int getCreditos() { return creditos; } /** * Retorna o login do estudante. O login é a combinação dos primeiros 4 caracteres do nome e dos * 3 primeiros caracteres de ID */ public String getLogin() { return noame.substring(0,4) + id.substring(0,3); } } /** * Imprime o nome e a identificação do estudante no terminal */ public void print() { System.out.println(name + " (" + id + ")"); } e faça os itens abaixo. a) Identifique os campos da classe. b) Como os objetos são criados? c) Como os conteúdos dos campos são acessados? d) Como o campo id é alterado? Por que? e) Explique o método getLogin. f) Observe o comando abaixo: Student estudante1 = new Student (“Carlos Camargo”,”738321”); Desenhe o diagrama do objeto criado. g) O que seria retornado por getLogin para o objeto criado acima? h) A classe String define um método de acesso length com a seguinte assinatura: /** * Retorna o numero de caracteres nessa string. /* public int length() Adicione instruções condicionais ao construtor de Student para imprimir uma mensagem de erro se o comprimento do parâmetro nomeCompleto tiver menos de quatro caracteres ou o comprimento do parâmetro idEstudente tiver menos de três caracteres. Pág.: 20 DET 111 – Programação de Computadores II Semestre 2012/II Mas o construtor ainda deve utilizar estes parâmetros para configurar os campos name e id, mesmo que a mensagem de erro seja impressa. Dica: utilize instruções if da seguinte forma para imprimir as mensagens de erro. if (realiza um teste sobre um dos parâmetros) { Imprime uma mensagem de erro se o teste der um resultado verdadeiro } Outros Exercícios (a) Analise a classe abaixo. Que informações os objetos criados a partir desta classe possuem? Que ações podem executar? Desenvolver o código desta classe em Java. Em seguida desenvolva uma aplicacação AppEleicao que simule a apuração de 1000 votos. Para gerar números podemos utilizar a classe Random. A documentação de classes em Java pode ser acessada pelo BlueJ no menu Help. Estude esta classe, descubra como os objetos podem ser criados e como podemos utilizar objeto desta classe para gerar votos para nossos candidatos, que são 1, 2 ou 3. Sua aplicação deverá computar os votos, mostrar a pontuação de cada um e o vencedor. Eleicao - votosCandidato1: int - votosCandidato2: int - votosCandidato3: int + Eleicao() // zera os votos de cada candidato + computaVoto(voto: int) // computa o voto para o devido candidato + getVotosCandidato1(): int // retorna o nº de votos do candidato 1 + getVotosCandidato2(): int // retorna o nº de votos do candidato 2 + getVotosCandidato3(): int // retorna o nº de votos do candidato 3 + mostraResultado() // exibe na tela o nº de votos de cada candidato + mostraVencedor() // apura o vencedor e mostra seu número (b) Observe a ilustração abaixo, cada ponto é representado por suas coordenadas cartesianas. y x (5,8.3) (-6,7) (0,0) x (-2,-2) (4.9,-1,5) A classe Ponto2D encapsula um ponto no espaço de duas dimensões: Ponto2D - x: double Comentários Campos privados da classe Pág.: 21 DET 111 – Programação de Computadores II Semestre 2012/II - y: double + Ponto2D(x: double, y: double) + éIgual(outroPonto: Ponto2D): boolean + origem: Ponto2D + distanciaA(outroPonto: Ponto2D): double Construtor: inicia os valores dos campos com os parâmetros retorna true se as coordenadas horizontais e verticais são iguais, false caso contrário retorna uma nova instância da própria classe Ponto2D contendo as coordenadas 0 e 0. Esta instância poderá ser usada diretamente por aplicações ou classes que executem este método sem a necessidade de criar uma nova instância com new retorna a distância entre o ponto considerado e outro ponto através da fórmula ( x 2 − x1) 2 + ( y 2 − y1) 2 Crie uma aplicação que crie os pontos seguintes e exiba a área do retângulo formado. (c) (5,8.3) (15,8.3) (5,1.5) (15,1.5) Escreva, em Java, a classe Empregada mostrada no diagrama abaixo. Empregado - primeiroNome: String - ultimoNome: String - cpf: String // deve ser feita a verificação dos dígitos verificadores do cpf - salarioMensal: doublé - numeroDependentes: int + Empregado(primeiro: String, ultimo: String, cpf: String) + setPrimeiroNome(primeiro: String) + getPrimeiroNome: String + setUltimoNome(ultimo: String) + getUltimoNome: String + setCpf(cpf: String) + getCpf: String + setNumeroDependentes(n: int) + getNumeroDependentes(): int + getAbanoFamilia(): float // retorna 1% do valor do salário mensal para cada dependente + getDescontoInss(): float // 8% salário até 868,29 // 9% de 868,30 a 1.447,14 Pág.: 22 DET 111 – Programação de Computadores II Semestre 2012/II // 11% 1.447,15 a 2.894,28 + getDescontoIRRF(): String // Até 1.164,00 – isento // De 1.164,01 a 2.326,00 – 15% // Acima de 2.326,00 – 25% + salarioLiquido(): double // retorna o salário mensal – desconto + abono Segue abaixo informações sobre como é feito o cálculo do dígito verificador do cpf. Cálculo dos dígitos verificadores do CPF O CPF é um número formado por 11 dígitos onde os dois últimos dígitos são chamados de dígitos verificadores (DV). Cada DV é calculado com base nos nove primeiros e servem para validar o número do CPF como um todo. Assim, quando se digita o número do CPF em um software que usa o algoritmo descrito a seguir ele tem condição de checar se o número está digitado corretamente, evitando, por exemplo, o cadastro de inválidos. Por exemplo, vamos pegar um número de 9 dígitos qualquer (123.456.789)criar um número de CPF (123.456.789-XY) calculando seus DVs (X e Y). O cálculo dos DVs é executado em duas etapas usando para isto o módulo de divisão 11 (módulo de divisão é a parte inteira do quociente de uma divisão). Etapa I - Cálculo do primeiro DV: 1) Cada um dos 9 dígitos iniciais é multiplicado por pesos variando de 10 até 2 da esquerda para a direita, de acordo com o seguinte quadro: 123456789 10 9 8 7 6 5 4 3 2 Assim obtemos: 1 2 3 4 5 6 10 x 9 x 8 x 7 x 6 x 5 x 10 18 24 28 30 30 7 8 4 x 3 28 24 9 x 2 18 2) Em seguida, calculamos a soma de todos os valores obtidos: (10+18+24+28+30+30+28+24+18) = 210 3) A soma resultante (210) será dividida por 11 sendo considerado somente a parte inteira do quociente (19). 4) Caso o resto da divisão seja menor que 2, o primeiro DV será 0 (zero). Caso contrário, subtrai-se de 11 o valor obtido. 5) Como o resto da divisão foi 1 (um) o DV é zero. Se o resto fosse, por exemplo, 7 (sete), o DV seria 4 (11-7=4). Resumindo: A soma dos produto dos dígitos vezes os respectivos pesos: 210. Dividindo por 11: quociente inteiro 19 e 1 (um) como resto. Como o resto da divisão é menor que 2, o primeiro DV é 0 (zero). Se não fosse subtrairíamos o valor obtido de 11. Assim o nosso CPF já tem uma parte: 123.456.789-0Y. Pág.: 23 DET 111 – Programação de Computadores II Semestre 2012/II Etapa II - Cálculo do segundo DV 1) Para o cálculo do segundo DV será considerado os 9 primeiros dígitos mais o primeiro DV (calculado como 0 (zero)). Montamos um quadro semelhante ao anterior, só que usaremos os pesos de 11 até 2 uma vez que temos mais um dígito nesse cálculo: 1 2 3 4 5 6 7 8 9 0 11 x 10 x 9 x 8 x 7 x6 x 5 x 4 x 3 x 2 11 20 27 32 35 36 30 32 27 0 Assim, como no cálculo do primeiro DV, multiplicamos cada dígito pelo seu respectivo peso... e obtemos a soma dos resultados: 11+20+27+32+35+36+35+32+27+0 = 255 2) Novamente, a soma resultante (255) será dividida por 11 sendo considerado somente a parte inteira do quociente (23). 3) Caso o resto da divisão seja menor que 2, o DV seria 0 (zero). Caso contrário, subtrairíamos de 11 o valor obtido. Como o resto da divisão de 255 por 11 é 2 temos: 11-2=9. Assim 9 (nove) é o nosso segundo DV. Assim o CPF do exemplo seria: 123.456.789-09. Curiosidade: O CPF 111.111.111-11 é um ótimo número para testes (e para quando não queremos digitar um CPF existente) pois é válido e muito fácil de memorizar. Pode ser um bom exercício para saber se foi tudo bem compreendido. ;-) Um pequeno gerador de DV feito em Basic, entre com os primeiros 9 dígitos para se obter o primeiro DV. Depois entre com os 9 dígitos mais o primeiro DV para obter o segundo DV: Function DVCPF(Matr As String) As String Dim X, Cont, Soma, DV As Integer Tam = Len(Matr) Cont = Tam + 1 Soma = 0 For X = 1 To Tam digito = CInt(Mid(Matr, X, 1)) Soma = Soma + (digito * Cont) Cont = Cont - 1 Next DV = Soma Mod 11 If DV < 2 Then DV = 0 Else DV = 11 - DV End If DVCPF = DV End Function (d) Escreva uma funcionalidades. aplicação que crie um objeto desta classe e mostre suas Pág.: 24 DET 111 – Programação de Computadores II Semestre 2012/II (e) Faça uma classe Conta cujos objetos gerados a partir dela contenham o nome do cliente, o numero da conta, o saldo e o limite. Estes valores deverão ser informados no construtor, sendo que o limite não poderá ser maior que o valor do salário mensal do cliente. Faca um método deposito e um método retira. O método retira ira devolver true ou false, dependendo se o cliente pode retirar. Faca um método saldo que retorne o saldo do cliente. (f) Faça uma classe produto que contenha o numero serial, o volume (inteiro) e também uma string que inicialmente possui o valor "não testado". O numero serial será passado no construtor. Deverá possuir um método booleano testaUnidade que somente poderá ser executado uma vez. O produto terá 90% de chance de estar OK. Caso esteja OK, a string passará de "não testado" para "aprovado". Caso não esteja OK, passara para "reprovado". Retorna true se foi aprovado e false se não foi. Deverá também conter um método setVolume e um método toString que retornará em uma string o número serial, o volume e o resultado do teste. (OBS: java.lang.Math.random() gera um numero de 0.0 a 1.0) Pág.: 25 DET 111 – Programação de Computadores II Semestre 2012/II 4. Construtores e sobrecarga Até agora, após criar uma instância da classe com a palavra-chave new, usamos métodos para inicializar os campos da instância. O uso desses métodos é de responsabilidade do programador usuário das classes – para criar as instâncias o compilador obriga o uso da palavra-chave new, mas não obriga o uso de métodos de inicialização. Assim, um programador pode criar a instância de uma classe e esquecer de inicializar seus dados. Observe a classe abaixo. class RegistroAcademicoSemConstrutor { private String nomeDoAluno; private int numeroDeMatricula; private byte codigoDoCurso; private Double percentualDeCobranca; public void inicializaRegi8stroAcademicoSemConstrutor(String n, int m, byte c, double p) { nomeDoAluno = n; numeroDeMatiricula = m; codigoDoCurso = c; percentualDeCobrança = p; } public double calculaMensalidade() { double mensalidade = 0; if (codigoCurso == 1) mensalidade = 450.00; if (codigoCurso == 2) mensalidade = 500.00; if (codigoCurso == 3) mensalidade = 550.00; if (codigoCurso == 4) mensalidade = 380.00; if (percentualDeCobranca == 0) mensalidade = 0; else mensalidade = mensalidade * 100.0 / percentualDeCobranca; return mensalidade; } } Class AppRegistroAcademicoSemConstrutor { public static void main (String args[]) { RegistroAcademicoSemConstrutor michel = new RegistroAcademicoSemConstrutor(); RegistroAcademicoSemConstrutor roberto = new RegistroAcademicoSemConstrutor(); michel.aluno1.inicializaRegistroAcademicoSemConstrutor(“Michel Alves”,012500”, (byte)2,100.0); System.out.println(“Mensalidade de Michel R$ = “+michel.aluno1.calculaMensalidade()); System.out.println(“Mensalidade de Roberto R$ = “+roberto..calculaMensalidade()); } } O resultado da execução da aplicação é: A mensalidade de Michel R$ = 500.0 A mensalidade de Roberto R$ = NaN OBS.: A divisão de zero por zero (quando ambos são valores ponto flutuante) é representada em Java como NaN (Not a Number). Em muitas situações será necessário forçar o programador a passar dados para as instâncias cridas em classes e progamas para que estas tenham sentido. Isso pode ser feito usando construtores. Pág.: 26 DET 111 – Programação de Computadores II Semestre 2012/II 4.1 Construtores Construtores são elementos especiais das classes que são chamados automaticamente quando instâncias são criadas através da palavra-chave new. Por meio da criação de construtores, podemos garantir que o código que eles contêm será executado antes de qualquer outro código em outros métodos, já que uma instância de uma classe só pode ser usada depois de ter sido criada com new, o que causará a execução do construtor. Construtores são úteis para inicializar campos de instâncias de classes, para garantir, que quando métodos dessas instâncias forem chamados, os campos contenham valores corretos. Caso os campos de uma instância não sejam inicializados, os seguintes padrões serão adotados: o Campos do tipo boolean inicializados com false; o Campos do tipo char com caracter cujo código unicode é zeroe que é impresso como um espaço; o Campos do tipo inteiros ou de ponto flutuante são zerados o Instâncias de qualquer classe, inclusive String, são inicializadas com null. Diferenças entre construtores e métodos: • Devem ter exatamente o mesmo nome da classe; • Não podem retornar valor, nem mesmo void; • Não devem ter modificadores como public ou private e serão públicos se a classe for pública. Quando classes criadas pelo programador não têm construtor declarado explicitamente, o compilador Java cria um construtor default, que não recebe parâmetros nem executa código. Quando o programador de classes cria um ou mais construtores, o compilador não inclui o construtor default. Para exemplificar o papel e a importância de construtores, observe o código da classe EventoAcademico, que representa um evento como congresso, simpósio ou reunião. public class Data { private byte dia,mês; private short ano; public void inicializaData(byte d, byte m, short a) { if (dataÉVálida(d,m,a)) { dia = d; mês = m; ano = a; } else { dia = 0; mês = 0; ano = 0; } } public byte getDia() { return dia; } public byte getMês() { return mês; } public short getAno() { return ano; } Pág.: 27 DET 111 – Programação de Computadores II Semestre 2012/II public boolean dataÉVálida(byte d, byte m, short a) { if ((d >= 1) && (d <= 31) && (m >= 1) && (m <= 12)) return true; else return false; } public String getData() { return dia+" / "+mês+" / "+ano; } } class EventoAcademico{ private String nomeDoEvento, localDoEvento; private Data inicioDoEvento, fimDoEvento; private int numeroDeParticipantes; public EventoAcademico(String n, String l, Data, i, Dat f, int num) { nomeDoEvento = n; localDoEvento = l; inicioDoEvento = new Data(); inicioDoEvento.inicializaData(i. get Dia(),i. get Mês();i. get Ano()); fimDoEvento = new Data(); fimDoEvento.inicializaData(f. get Dia(),i.get Mês();i. get Ano()); numeroDeParticipantes = num; } public String toString() { String relatório = “”; relatório = relatório + “Evento: “+ nomeDoEvento+”\n”; relatório = relatório + “Local: “+ localDoEvento+”\n”; relatório = relatório + “De: “+ inicioDoEvento.getData()+”\n”; relatório = relatório + “a: “+ fimDoEvento.getData()+”\n”; relatório = relatório + “Participantes: “+ numeroDeParticipantes+”\n”; return relatório; } } Como campos que são objetos de outras classes são inicializados? Ao construir o objeto do tipo EventoAcademico teremos uma referência aos objetos do tipo Data ou uma cópia exata dos dados? que? Podemos criar um objeto do tipo EventoAcademico com a seguinte construção? Por EventoAcademico semanaAcademica2011_2 = new EventoAcademico(); 4.2 Sobrecarga de métodos Em algumas situações é útil poder executar métodos em uma classe passando mais ou menos parâmetros, conforme a necessidade. Considere o exemplo da classe ContaBancariaSimplificada. Seu construtor não recebe parâmetros algum e apenas limpa os campos. E se ao criarmos a conta já tivermos todos os dados do cliente? Seria bom ter um construtor que permitisse passar automaticamente o nome e informar se a conta é especial, por exemplo. Uma solução seria ter métodos diferentes para cada solução. O problema é que ficará a cargo do programador chamar o método específico. Pág.: 28 DET 111 – Programação de Computadores II Semestre 2012/II Java e outras linguagens permitem a criação de métodos com nomes iguais, contanto que as suas assinaturas sejam diferentes (assinatura = nome +parâmetros). O tipo de retorno não é considerado parte da assinatura. A possibilidade de termos métodos com mesmo nome e assinaturas diferentes é chamado sobrecarga de métodos. A decisão de qual chamar fica por conta da assinatura. Cada instância possui uma auto-referência em Java. Essa referência é representada pela palavra-chave this. Para chamar um construtor de dentro de outro construtor basta usar a palavra this substituindo o nome do construtor. Veja o exemplo considerando dois construtores da classe ContaBancaria: ContaBancaria(String pNome) { nome = pNome; } ContaBancaria(String pNome, boolean pEEspecial) { this(pNome); eEspecial = pEEspecial; } A palavra chave this também é útil em casos onde é preciso diferenciar argumentos (parâmetros) e campos. Veja o exemplo: ContaBancaria(String nome, boolean eEspecial) { this.nome = nome; this.eEspecial = eEspecial; } Nestas linhas temos que o elemento do objeto com nome nome (campo nome= this.nome) recebe o parâmetro nome e o campo eEspecial recebe o parâmetro eEspecial. Um cuidado deve ser tomado pelo programador das classes quando criar métodos sobrecarregados: Java permite que alguns tipos nativos de dados sejam aceitos como sendo de outros tipos, contanto que nada se perca na representação. Assim, um valor do tipo byte pode ser aceito quando um método espera por um int, já que este pode representar byte sem perda de informação. O mesmo não ocorre quando um método ou construtor espera por um tipo e a chamada contenha um tipo de dados que nem sempre pode ser contido no esperado, por exemplo, nem sempre um doublé pode ser representado por um int. Em muitos casos podemos usar a conversão explícita ou cast para forçar o rebaixamento, geralmente com perda de precisão. Atividade Desenvolva uma aplicação, AppEventoAcademico, que permita cadastrar vários eventos, obtendo as informações do usuário por meio de caixas de diálogos de entrada da classe JOptionPane. Sua aplicação deverá contar o número de participantes de todos os eventos e exibir ao final este total. Segue abaixo a classe Contador. Observe que o método incrementa da classe Contador aumenta o campo contagem de um em um. Crie outro método com o mesmo nome, porém com um parâmetro do tipo int que permita fornecer uma quantidade inteira para que esta possa ser contada, isto é, faça uma sobrecarga no método incrementa. Coloque também um método set e outro get para cada campo da classe EventoAcademico. Pág.: 29 DET 111 – Programação de Computadores II Semestre 2012/II public class Contador { private int contagem; public Contador() { contagem = 0; } public void incrementa() { contagem++; } } 5. public int quantos() { return contagem; } Campos e Métodos Estáticos Introdução Neste tópico veremos como declarar campos que serão compartilhados entre todas as instâncias de uma mesma classe em uma aplicação, assim como a criação de métodos que não precisam de instâncias de classes para ser executados. Campos estáticos ou campos de classes Campos estáticos em uma classe são compartilhados por todas as instâncias dessa classe. Caso este valor seja alterado por alguma instância dessa classe a modificação será refletida em todas as instâncias dessa classe. São declarados com o modificador static que deve ser declarado antes do tipo de dado do campo e pode ser combinado com public e private. As duas principais utilidades são manter uma informação para todas as instâncias de uma classe que possa ser alterada ou acessada por qualquer instância e armazenar valores que não serão constantes. Considere a simulação de fila em um banco com e sem fila única. public class SimuladorCaixaBanco0 { private int numeroDoCliente; private int numeroDoCaixa; SimuladorCaixaBanco0(int n) { numeroDoCaixa = n; numeroDoCliente = 0; System.out.println("Caixa "+numeroDoCaixa+" iniciou operação."); } } public void proximoAtendimento(){ numeroDoCliente = numeroDoCliente + 1; System.out.print("Cliente com a senha nº "+numeroDoCliente+" , favor "); System.out.println("dirigir-s ao caixa nº "+numeroDoCaixa+"."); } Pág.: 30 DET 111 – Programação de Computadores II Semestre 2012/II public class DemoSimuladorCaixaBanco0 { public static void main (String arg[]) { SimuladorCaixaBanco0 c1 = new SimuladorCaixaBanco0(1); SimuladorCaixaBanco0 c2 = new SimuladorCaixaBanco0(2); SimuladorCaixaBanco0 c3 = new SimuladorCaixaBanco0(3); SimuladorCaixaBanco0 c4 = new SimuladorCaixaBanco0(4); SimuladorCaixaBanco0 c5 = new SimuladorCaixaBanco0(5); c1.proximoAtendimento(); c2.proximoAtendimento(); c3.proximoAtendimento(); c4.proximoAtendimento(); c5.proximoAtendimento(); c1.proximoAtendimento(); c2.proximoAtendimento(); c3.proximoAtendimento(); c1.proximoAtendimento(); c2.proximoAtendimento(); c1.proximoAtendimento(); c1.proximoAtendimento(); c1.proximoAtendimento(); c1.proximoAtendimento(); } } Caixa 1 iniciou operação. Caixa 2 iniciou operação. Caixa 3 iniciou operação. Caixa 4 iniciou operação. Caixa 5 iniciou operação. Cliente com a senha nº 1 Cliente com a senha nº 1 Cliente com a senha nº 1 Cliente com a senha nº 1 Cliente com a senha nº 1 Cliente com a senha nº 2 Cliente com a senha nº 2 Cliente com a senha nº 2 Cliente com a senha nº 3 Cliente com a senha nº 3 Cliente com a senha nº 4 Cliente com a senha nº 5 Cliente com a senha nº 6 Cliente com a senha nº 7 , , , , , , , , , , , , , , favor favor favor favor favor favor favor favor favor favor favor favor favor favor dirigir-s dirigir-s dirigir-s dirigir-s dirigir-s dirigir-s dirigir-s dirigir-s dirigir-s dirigir-s dirigir-s dirigir-s dirigir-s dirigir-s ao ao ao ao ao ao ao ao ao ao ao ao ao ao caixa caixa caixa caixa caixa caixa caixa caixa caixa caixa caixa caixa caixa caixa nº nº nº nº nº nº nº nº nº nº nº nº nº nº 1. 2. 3. 4. 5. 1. 2. 3. 1. 2. 1. 1. 1. 1. O próximo código permite que campos sejam compartilhados, independente de quantas instâncias sejam criadas. Observe o exemplo e a demonstração utilizando objetos desta classe. public class SimuladorCaixaBanco { static private int numeroDoCliente; private int numeroDoCaixa; SimuladorCaixaBanco0(int n) { numeroDoCaixa = n; numeroDoCliente = 0; System.out.println("Caixa "+numeroDoCaixa+" iniciou operação."); } Pág.: 31 DET 111 – Programação de Computadores II Semestre 2012/II public void proximoAtendimento(){ numeroDoCliente = numeroDoCliente + 1; System.out.print("Cliente com a senha nº "+numeroDoCliente+" , favor "); System.out.println("dirigir-s ao caixa nº "+numeroDoCaixa+"."); } } Caixa 1 iniciou operação. Caixa 2 iniciou operação. Caixa 3 iniciou operação. Caixa 4 iniciou operação. Caixa 5 iniciou operação. Cliente com a senha nº 1 , favor dirigir-s ao caixa nº 1. Cliente com a senha nº 2 , favor dirigir-s ao caixa nº 2. Cliente com a senha nº 3 , favor dirigir-s ao caixa nº 3. Cliente com a senha nº 4 , favor dirigir-s ao caixa nº 4. Cliente com a senha nº 5 , favor dirigir-s ao caixa nº 5. Cliente com a senha nº 6 , favor dirigir-s ao caixa nº 1. Cliente com a senha nº 7 , favor dirigir-s ao caixa nº 2. Cliente com a senha nº 8 , favor dirigir-s ao caixa nº 3. Cliente com a senha nº 9 , favor dirigir-s ao caixa nº 1. Cliente com a senha nº 10 , favor dirigir-s ao caixa nº 2. Cliente com a senha nº 11 , favor dirigir-s ao caixa nº 1. Cliente com a senha nº 12 , favor dirigir-s ao caixa nº 1. Cliente com a senha nº 13 , favor dirigir-s ao caixa nº 1. Cliente com a senha nº 14 , favor dirigir-s ao caixa nº 1. Outra utilidade de campos estáticos é a criação de constante, que serão utilizadas por todas as instâncias das classes. Constantes em classes geralmente são acessíveis através da classe e não de instâncias dessa classe. Observe o exemplo abaixo: public class ConstantesMatematicas { final static public double raizDe2 = 1.4142135623730950488; final static public double raizDe3 = 1.730508075688772935; final static public int meses = 12; } public class DemoConstantes { public static void main(String arg[]) { ConstantesMatematicas c1 = new ConstantesMatematicas(); System.out.println("Raiz de 2 = "+c1.raizDe2); System.out.println("Raiz de 2 = "+ConstantesMatematicas.raizDe2); System.out.println("meses = "+ConstantesMatematicas.meses); } } Raiz de 2 = 1.4142135623730951 Raiz de 2 = 1.4142135623730951 meses = 12 Métodos estáticos em classes Métodos estáticos também são declarados com static, que deve preceder o tipo de retorno do método e que pode ser combinado com modificadores de acesso. Os métodos estáticos podem ser chamados sem a necessidade de criação de instâncias da classe às quais pertencem. Pág.: 32 DET 111 – Programação de Computadores II Semestre 2012/II Um exemplo é o método main. A aplicação mais freqüente de métodos estáticos é a criação de bibliotecas de métodos. Observe o exemplo na classe ConversaoDeComprimento. public class ConversaoDeComprimento { public static double polegadasParaCentimetros(double polegadas) { double centimetros = polegadas * 2.54; return centimetros; } public static double pésParaCentimetros(double pés) { double centimetros = pés * 30.48; return centimetros; } } public static double milhasParaQuilometros(double milhas) { double quilometros = milhas * 1.609; return quilometros; } class AppConversaoUnidades { public static void main(String args []) { ConversaoDeComprimento conversao1 = new ConversaoDeComprimento(); System.out.println("Vinte pés são :"+conversao1.pésParaCentimetros(20)+" centímetros."); System.out.println("Cinco polegadas são: "+conversao1.polegadasParaCentimetros(5)+" centímetros."); System.out.println("Vinte pés são :"+ConversaoDeComprimento.pésParaCentimetros(20)+" centímetros."); System.out.println("Cinco polegadas são: "+ConversaoDeComprimento.polegadasParaCentimetros(5)+" centímetros."); } } Pág.: 33 DET 111 – Programação de Computadores II Semestre 2012/II 6. Estruturas de decisão e controle condicionais Operadores lógicos em Java == != > < >= <= Retorna Retorna Retorna Retorna Retorna Retorna True True True True True True se se se se se se os dois os dois o valor o valor o valor o valor valores forem exatamente iguais e False caso contrário valores forem diferentes e False se forem exatamente iguais à esquerda for maior que o valor à direita à esquerda for menor que o valor à direita à esquerda for maior ou igual que o valor à direita à esquerda for menor ou igual que o valor à direita Os operadores acima podem ser usados para comparar valores de tipos nativos numéricos (inclusive char). Referências às instâncias de classes podem ser comparadas com == e !=, mas os resultados geralmente são inesperados e incorretos: duas referências diferentes a instâncias de classes contendo os mesmos dados serão diferentes quando comparadas. Instâncias da classe String devem ser utilizadas usando métodos específicos, por exemplo, o método equals. Valores do tipo boolean e resultados de operações ou métodos que retornem valores booleanos podem ser combinados entre si com os operadores && (AND), || (OR) e ! (NOT). Estruturas de decisão e execução seletiva if-else if (valor-ou- if ((diaDaSemana >= 3) && (diaDaSemana <=5)) expressão) preço = 4; comando-ou-bloco else else if ((idade <= 14) || (idade >= 65)) comando-ou-bloco preço = 4; else preço = 8; Operador valor = (exp ? exp- int valor = (p1 > p2 ? p1 : p2) // se p1 > p2 valor conidicional ? se-verdadeiro : exp- recebe p1 senão recebe p2 se-falso) Switch switch(exp-retorneswitch (mes) { inteiro-ou-de-menorcase 1: res = “Janeiro”; break; precisao) { case 2: res = “Fevereiro”;break; ... ... } } switch (mês) { case 2: numeroDias = 28; break; case 4: case 6: case 9: case 11: numeroDias = 30; break; default: numeroDias = 31; break; } Estruturas de decisão e controle de repetição Pág.: 34 DET 111 – Programação de Computadores II Semestre 2012/II As estruturas de repetição em Java são chamadas coletivamente de laços. Uma tarefa inerente à execução de laços em Java é a modificação de variáveis que controlam a execução de um laço, por exemplo, de um contador que contará quantas vezes a repetição será feita. Um caso especial de variáveis de controle são contadores, mostrados a seguir. Contadores ++ += --= *= /= Quando aplicado a variáveis do tipo inteiro ou ponto flutuante incrementará o valor da variável de um. a++ tem mesmo efeito de a = a +1. O operador ++ pode ser usado antes ou depois do nome da variável que incrementará. Aparentemente não existe diferença entre aplicar o operador antes ou depois da variável, mas quando lembramos que o operador, alem de modificar o conteúdo da variável, retorna o valor modificado, a diferença fica patente. Ex.: int cont = 17; ao final do código val = cont++; a variável val valerá 17, pois o operador retorna o valor da variável cont antes de incrementá-la. Por outro lado,l se a variável cont valer 17, ao final do código val = ++cont; ambas as variáveis valerão 18. Incrementa o valor da variável usando o argumento como incremento. short val = 800; val += 200; a variável val valerá 1000. Decrementa o valor da variável em um. O comando z--poderia ser escrito como z = z – 1. O operador --, como o ++, pode ser aplicado antes ou depois da variável que será modificada. Este comando decrementará o valor da variável usando o argumento para o decremento. Ex.: float méd = 49.5f; méd -= 11.04; a variável med valerá 38.46 (med = med – 11.04. Este comando multiplicará o valor da variável usando o argumento passado. Ex.: doublé j = 735.5; j *= 4; j valerá 2930 (j = j * 4). Este comando dividirá o valor da variável usando o argumento passado. Ex.: int v = 2000; v /= 12; v valerá 166 (o = o / 12). Repetições Formato geral while (condição) comando ou bloco-de-comando (entre { e }); do { comando ou bloco-de-comando } while (condição); for (inicialização; verificação-de-condições; atualização) comando-ou-bloco; • Inicialização = comandos que devem ser executados antes da repetição • Verificação = geralmente uma expressão booleana que é verificada antes de cada iteração • Atualização = pode conter comandos que serão executados após o final de cada iteração. Recursão: Técnica de programação na qual um algoritmo, para ser executado, chama o próprio algoritmo para resolver parte menor do problema, desta forma quebrando o problema em pedaços menores. Ex.: algoritmo para calcular a somatória Exemplo double valor = 1; while (valor < 2000) { System.out.println(valor); Valor *= 2; } O bloco de comandos da repetição será executado pelo menos uma vez. Enquanto a condição for verdadeira os comandos serão repetidos. for (contador = 200; contador >= 0; contador -= 10) System.out.println(contador); static long somatoria(int n) { if (n == 0) { return 0; else return n + somatoria(n-1); } Pág.: 35 DET 111 – Programação de Computadores II Semestre 2012/II } dos N primeiros números inteiros, que é igual a soma de N com os N-1 primeiros números, que por Fib(0) = 1 sua vez é igual a N-1 mais a somatória de N-2 Fib(n) = Fib(1) =1 números inteiros e assim sucessivamente. Fib(n) = Fib(n-1) + Fib(n-2) Evidentemente quando N for igual a zero a somatória será zero e fim. Vamos implementar? A implementação de recursão usando linguagens de programação sugere o uso de métodos que serão chamados com argumentos que delimitam ou simplificam cada vez mais o algoritmo a ser resolvido e que, quando o algoritmo não puder ser mais simplificado, retornem uma operação ou valor qualquer. Algumas sugestões para otimização de repetições 1. Evite o recálculo de expressões invariantes em laços 2. Para repetições com contadores simples utilize o tipo int para a variável de controle. Laços com variáveis de controle do tipo long, float e double executarão mais lentamente. 3. Evite repetições curtas, substituindo-as onde for possível. 4. Evite chamadas a métodos quando existirem maneiras de efetuar operações diretamente. Pág.: 36 DET 111 – Programação de Computadores II Semestre 2012/II 7. Exercícios Desenvolva em Java os exercícios abaixo 1. Escreva uma classe que contenha métodos estáticos para retornar o maior e o menor entre dois, três e quatro valores, considerando que os argumentos e o tipo de retorno podem ser tanto int quanto double. Dica: os métodos podem ser chamados em cascata, por exemplo, para calcular o maior de três valores (a, b e c) pode-se calcular o maior entre dois (a e b) e comparar o resultado com o terceiro valor (c). 2. Observe a classe abaixo: RegistroAcademico - nomeAluno: String - numeroMatricula: int (estático) - codigoCurso: byte //inicia com 0 - percentualCobrança: double + RegistroAcademico(nome,curso,p) + calculaMensalidade(): double + getDados: String codigoCurso deverá ser constante, seguindo o padrão abaixo: 1. Medicina (2300,00) 2. Nutrição (1150,00) 3. Administração (1200,00) 4. Engenharia de Alimentos (1750,00) Crie esta classe em Java e crie um aplicativo onde se colete dados pelo teclado e cadastre alguns alunos gerando o número de matrícula automaticamente. O campo deve ser iniciado com zero e toda nova instância incrementá-lo. 3. Desenvolva uma classe para implementar os itens abaixo: a. Fatorial(n) = 1, se n = 0 n * Fatorial(n-1), se n > 0 b. Soma(n) = 0, se n = 0 n+Soma(n-1), se n > 0 c. Cálculo do máximo divisor comum (MDC) de forma recursiva. Se os dois números são iguais o MDC é o próprio número, caso o primeiro seja maior que o segundo atualiza-se o primeiro com a subtração do primeiro pelo segundo e caso o segundo seja maior, atualiza-se o segundo com a subtração do segundo pelo primeiro. E se repete a chamada até que os números sejam iguais. Na pior das hipóteses, os dois serão iguais a 1. d. Implemente a função que calcula o n-ésimo termo da sequência de Fibonacci. e. O cálculo da exponenciação, isto é, o resultado da operação de uma base elevada a um expoente. f. Desenvolva uma aplicação que possua um menu com as opções de funções recursiva implementadas e execute de acordo com a opção e apenas termine quando a opção Sair for selecionada. g. Escreva uma classe Serie que encapsule o mecanismo de geração de séries numéricas como as usadas em testes de raciocínio, onde uma pessoa deve deduzir a regra que gerou os números e acertar os próximos números da série. A série deve ser gerada usando três valores: inicial, multiplicador e adicional, de forma que o primeiro número da série seja igual ao inicial, o segundo será calculado como (inicial + adicional) * multiplicador e o terceiro como (segundo + adicional) * multiplicador e assim por diante. Os valores devem ser passados para o construtor da classe e usados por um método, Pág.: 37 DET 111 – Programação de Computadores II Semestre 2012/II imprime, que recebe como argumento o número de termos que serão impressos. Por exemplo, uma classe poderia criar três instâncias da classe Serie e imprimir respectivamente, os primeiros 10, 12 e 14 termos, com o trecho de código abaixo: Serie s1 = new Serie(0,-2,2); s1.imprime(10); Serie s2 = new Serie(1,2,0); s2.imprime(12); Serie s3 = new Serie(1,1,2); s3.imprime(14); Resultaria em 0 –4 4 –12 20 –44 84 –172 340 –684 1 2 4 8 16 32 64 128 256 512 1024 2048 1 3 5 7 11 13 15 17 19 21 23 25 27 Pág.: 38 DET 111 – Programação de Computadores II Semestre 2012/II 8. Reutilização de Classes Introdução Uma das características mais interessantes em POO é a capacidade de facilitar a reutilização de código que diminui a necessidade de escrever reescrever métodos e classes, economizando o trabalho do programador e diminuindo a possibilidade de erros. Existem dois mecanismos básicos de reutilização de classes em Java: delegação (ou composição – a nova classe contem campo que é uma instância da classe base) e herança (a nova classe é extensão da direta da classe base). Delegação ou Composição Observe o exemplo que segue onde são mostradas duas classes Data e AlunoAcademia. Onde está a COMPOSIÇÃO? public class Data { private byte dia,mês; private short ano; public void inicializaData(byte d, byte m, short a) { if (dataÉVálida(d,m,a)) { dia = d; mês = m; ano = a; } else { dia = 0; mês = 0; ano = 0; } } public byte getDia() { return dia; } public byte getMês() { return mês; } public short getAno() { return ano; } public boolean dataÉVálida(byte d, byte m, short a) { if ((d >= 1) && (d <= 31) && (m >= 1) && (m <= 12)) return true; else return false; } public String getData() { return dia+" / "+mês+" / "+ano; } } Pág.: 39 DET 111 – Programação de Computadores II Semestre 2012/II public class AlunoAcademia { private static int matricula = 0; private String nome; private float peso; private float altura; public Data dataNascimento; AlunoAcademia(String n, float p, float a, Data d) { nome = n; peso = p; altura = a; dataNascimento = d; matricula = matricula + 1; } public void setNome(String n) { nome = n; } public void setPeso(float p) { peso = p; } public void setAltura(float a) { altura = a; } public void setDataNascimento(Data d) { dataNascimento = d; } public float getIMC() { return peso/(altura*altura); } public String getFicha() { String s = "Nome: "+nome; s = s + "Matrícula: "+matricula; s = s + "Peso: "+peso; s = s + "Altura: "+altura; s = s + "Data de Nascimento: "+dataNascimento.getData(); s = s + "IMC: "+getIMC(); return s; } } Delegação e Modificadores de Acesso • PERGUNTA: O que aconteceria se tentássemos acessar o campo dia da data a partir da classe AlunoAcademia como o comando dataNascimento.dia = (byte)15;? • RESPOSTA: Teríamos a mensagem dia has private access in Data. Pág.: 40 DET 111 – Programação de Computadores II Semestre 2012/II • PERGUNTA: E quanto aos campos públicos, o que podemos dizer? O campo dataNascimento é público mas não posso colocar dataNascimento.dia = (byte)15. Por que? Delegação e Construtores Se for obrigatória a execução do construtor de uma instância da classe mãe, este pode ser chamado em qualquer método da própria classe, mas idealmente deve ser chamado a partir do construtor da própria classe. Herança Com o mecanismo de reaproveitamento por delegação ou composição permite a reutilização de classes já existentes como instâncias de novas classes. As classes originais ficam contidas na nova classe. Este mecanismo é útil quando consideramos que a classe que reutiliza instâncias de outras é composta das outras classes. Nem sempre o mecanismo de delegação é o mais natural para reutilização de classes já existentes, embora seja simples. Em especial, quando queremos usar uma classe como base à criação de outra mais especializada, a relação de composição imposta pelo uso da delegação acaba por criar soluções pouco naturais. Java permite reutilizar classe através do mecanismo de herança, que permite que criemos uma classe usando outra como base e descrevendo ou implementando as diferenças e adições da classe usada como base, reutilizando campos e métodos não privados da classe base. O mecanismo de herança é o mais apropriado para criar relações é-um-tipo-de entre classes. Observe o diagrama de classes e o código das classes que seguem. public class Data { private byte dia,mês; private short ano; public void inicializaData(byte d, byte m, short a) { if (dataÉVálida(d,m,a)) { dia = d; mês = m; ano = a; } else { dia = 0; mês = 0; ano = 0; } } public byte retornaDia() { return dia; } public byte retornaMês() { return mês; } public short retornaAno() { return ano; } public boolean dataÉVálida(byte d, byte m, short a) { if ((d >= 1) && (d <= 31) && (m >= 1) && (m <= 12)) return true; else return false; } Pág.: 41 DET 111 – Programação de Computadores II Semestre 2012/II } public String toString() { return dia+" / "+mês+" / "+ano; } public class Pessoa { private String nome; private String identidade; private Data dataNascimento; public void setNome(String nome) { this.nome = nome; } public void setIdentidade(String id) { this.identidade = id; } public void setDataNascimento(Data data) { this.dataNascimento = data; } public String getNome() { return this.nome; } public String getIdentidade() { return this.identidade; } public Data getDataNascimento() { return this.dataNascimento; } public float calculaEmprestimo() { return 1000.0f; } public String toString() { return "Nome: " + getNome() + "\nID: " + getIdentidade() + "\nData: " + dataNascimento.toString(); } } public class Funcionario extends Pessoa { private Data dataAdmissao; private float salario; } public void setDataAdmissao(Data data) { this.dataAdmissao = data; } public void setSalario(float salario) { this.salario = salario; } public Data getDataAdmissao() { return this.dataAdmissao; } public float getSalario() { return this.salario; } public float calculaEmprestimo() { return 4*getSalario(); } public String toString() { return super.toString() + "\nData admissão: " + dataAdmissao.toString() + "\nSalário: " + this.salario; } public class ChefeDepartamento extends Funcionario { private String departamento; Pág.: 42 DET 111 – Programação de Computadores II Semestre 2012/II private Data promocaoAChefe; public void setDepartamento(String departamento) { this.departamento = departamento; } public void setPromocaoAChefe(Data data) { this.promocaoAChefe = data; } public String getDepartamento() { return this.departamento; } public Data getPromocaoAChefe() { return this.promocaoAChefe; } public String toString() { return super.toString() + "\nDepartamento: " + departamento + "\nPromovido em: " + promocaoAChefe.toString(); } } Pág.: 43 Observações: • No diagrama temos as classes Funcionario e PacienteDeClinica herdando da classe Pessoa. • Uma subclasse conterá todos os campos e métodos declarados na superclasse mais os campos e métodos da própria classe . • O mecanismo de herança funciona somente em um sentido: da classe ancestral para a classe estendida, significando que a classe Funcionario terá acesso direto ou indireto aos campos da classe Pessoa, mas a classe Pessoa não terá acesso aos campos e métodos da classe Funcionario. • As classes Funcionario e PacienteDeClinica possuem campos em comum porque ambas herdam de Pessoa, mas não existe relação direta entre as duas classes estendidas. • Todas as classes em Java descendem de uma classe Object – mesmo que a declaração extends Object seja omitida. Esta classe não contém campos ou métodos úteis, não devendo ser usada diretamente, servindo para declarar métodos genéricos (como toString), que todas as classes devem implementar através de sobreposição. A palavra chave super Através da palavra chave super temos acesso a métodos das superclasses, aumentando assim, a reutilização de código. Existem duas maneiras de reutilizar métodos de classes ancestrais que não tenham sido declarados como private: se a execução for a mesma, instâncias da subclasse podem chamar diretamente o método como se fosse delas mesmas (exemplo é a chamada de qualSalário dentro da classe ChefeDeDepartamento). A segunda forma ocorre quando precisamos executar uma operação que não existe na superclasse. Isto ocorre normalmente em construtores onde temos que iniciar campos da superclasse e acrescentar campos da subclasse. Neste caso usamos super (que referencia a superclasse). Algumas regras para a chamada de super: • Construtores são chamados apenas com super seguida dos parâmetros, quando existirem. • Métodos são chamados pela palavra super seguida de ponto e do nome do método. Colocando os parâmetros quando existirem. • Construtores de superclasse só podem ser chamados dentro de construtores da subclasse e, mesmo assim, somente se forem declarados na primeira linha de código do construtor da classe • Somente métodos e construtores da superclasse imediata podem ser chamados usando a palavra chave super. Sobreposição e ocultação Utilizando o mecanismo de herança podemos definir novos campos e métodos em classes herdeiras e também redeclarar campos e métodos que têm a mesma assinatura de métodos declarados em classes ancestrais, mas com funcionalidade diferente. A declaração de métodos com a mesma assinatura que métodos de classes ancestrais chama-se sobreposição ou superposição. A declaração de campos em uma classe descendente com o mesmo nome de campos da classe ancestral chama-se ocultação. A sobreposição é bastante útil e comum em classes herdeiras, a ocultação de campos não oferece muitas vantagens, e as poucas oferecidas podem facilmente ser implementadas através de métodos que retornam valores e são superpostos de acordo com a necessidade. Algumas regras quanto a sobreposição seguem abaixo: • A sobreposição não elimina o acesso ao método da classe mãe, use a palavra-chave super. • Métodos de subclasses com o mesmo nome mas assinaturas diferentes dos métodos da superclasse não sobrepõem estes métodos. • A sobreposição pode ser feita com diferentes modificadores de acesso, contanto que os métodos sobrepostos tenham modificadores de acesso menos restritivos. • Métodos estáticos de classes ancestrais não podem ser sobrepostos em classes descendentes. • Se um campo é declarado em uma superclasse e oculto em subclasses, e métodos que acessam este campo são herdados, estes métodos farão referência ao campo da classe onde foram declarados. • Qualquer método da subclasse podem chamar qualquer método da superclasse que tenham sido declarados como public, protected ou sem declaração explícita de modificador. Métodos privados não são acessíveis diretamente, mas podem ser chamados indiretamente a partir de métodos que não sejam privados. • Métodos declarados como final são herdados por classes filhas, porém não podem ser sobrepostos. Exercício Desenvolva uma classe chamada TesteReuso que instancie dois objetos: • pessoa1 da classe Pessoa com dados inventados por você • func1 da classe Funcionário com dados inventados por você Escreva também os comandos para exibir os dados armazenados em cada objeto na tela. Para finalizar, desenhe os diagramas dos objetos criados. Polimorfismo O mecanismo de herança permite criar uma hierarquia de classes com relações é-umtipo-de, de forma que a partir de uma classe genérica, classes mais especializadas possam ser criadas. Este tipo de relação permite a existência de outra característica fundamental em linguagens de programação orientada a objetos: polimorfismo (muitas formas). Polimorfismo permite a manipulação de instâncias de classes que herdam de uma mesma classe ancestral de forma unificada. import java.util.Date; public class DemoPolimorfismo { public static void main (String a[]) { Pessoa p1 = new Pessoa("Carlos","12345-6",new Date(1,1,1980)); Funcionario f1 = new Funcionario("Manoel","789456-7", new Date(2,2,1970), new Date(3,3,200),1500f); System.out.println("Salário: 1000,00 Empréstimo: "+ p1.calculaEmprestimo()); System.out.println("Salário: "+f1.qualSalário()+ " Empréstimo: "+f1.calculaEmprestimo()); } } 9. Arrays em Java Introdução Arrays são estruturas e dados em Java que permitem o armazenamento de várias variáveis de um mesmo tipo ou instâncias de uma mesma classe usando uma única referência e um índice de acesso. Por exemplo, um array pode armazenar os dados de alunos de turma de 30 alunos. Arrays unidimensionais A declaração de arrays em Java é feita usando a notação dos colchetes: uma variável declarada como sendo de um tipo específico seguida de um par de colchetes será uma referência a um array de um elementos daquele tipo. Exemplos: int [] posição; char [] vogais; double[] alturaTurma; Não basta declarar as referências a arrays, estas devem ser inicializadas. O trecho de código abaixo mostra várias maneiras de inicializar arrays. int[] posição = new int [50]; char[] vogais = {'a','e','i','o','u'}; double[] alturaTurma; double[] alturaTurma2 = alturaTurma; O índice para acesso de um array deverá ser um valor entre zero e o tamanho do array menos um. O índice para acessar um elemento de um array deve ser sempre inteiro e positivo. Na inicialização do array devemos especificar o seu tamanho entre colchetes. Esse tamanho não precisa ser uma constante definida em tempo de execução. O tamanho mínimo aceitável para um array é zero: como os índices são contados a partir de zero, um array declarado de tamanho zero terá um único elemento. Um array não pode ter seu tamanho modificado, embora possamos usar a referência para apontar para outro array. Arrays que deverão representar valores constantes podem ser inicializados diretamente com os valores dos elementos do array, que devem ser especificados como uma lista de valores do tipo dos elementos do array, separados por vírgulas e cercados por chaves. Quando existe um campo que é um array, este deve ser inicializado no construtor da classe. O campo estático length do tipo final, fornece o número de elementos do array. Quando temos array composto de elementos de tipos nativos, estes devem ser do mesmo tipo ou compatível. Quando se trata de array de instâncias de classes, este pode ser constituído de objetos pertencentes a classes da hierarquia. Um exemplo de uso de vetores com elementos de tipo nativo segue na classe Array DeFloats. public class ArrayDeFloats { private float [] array; ArrayDeFloats(int numero) { array = new float[numero]; } public int tamanho() { } return array.length; public void modifica(int posicao, float valor) { if ((posicao >= 0) && (posicao < array.length) ) array[posicao] = valor; } public float valor(int posicao) { if ((posicao >= 0) && (posicao < array.length) ) return array[posicao]; else return Float.NaN; } public float[] paraArray() { return array; } public float menorValor() { float menorAtéAgora = array[0]; for (int i = 0; i < array.length; i++) if (array[i] < menorAtéAgora) menorAtéAgora = array[i]; return menorAtéAgora; } public float maiorValor() { float maiorAtéAgora = array[0]; for (int i = 0; i < array.length; i++) if (array[i] > maiorAtéAgora) maiorAtéAgora = array[i]; return maiorAtéAgora; } public String toString() { String resultado = "O array tem "+array.length+" elementos:\n"; for (int i = 0; i < array.length; i++) resultado += array[i]+ " "; return resultado; } } public class AppArrayDeFloats { public static void main (String args[]) { ArrayDeFloats af = new ArrayDeFloats(25); for (int i = 1; i < 40; i ++) af.modifica(i,(float)1/i); System.out.println(af); System.out.println("Maior valor = "+af.maiorValor()); System.out.println("Menor valor = "+af.menorValor()); System.out.println("Na posição 0 = "+af.valor(0)); System.out.println("Na posição 24 = "+af.valor(24)); System.out.println("Na posição 25 = "+af.valor(25)); } float[] cópia = af.paraArray(); System.out.println("CÓPIA"); System.out.println("Na posição 0 = "+cópia[0]); System.out.println("Na posição 0 = "+af.paraArray()[0]); } Observe a classe abaixo: public class Aluno { private String nome; private float[] notas; private int numeroAvaliacoes; public Aluno(String nome) { this.nome = nome; notas = new float[4]; numeroAvaliacoes = 0; } public String getNome() { return nome; } public boolean setNota(float n) { if (numeroAvaliacoes >= 4) return false; else { notas[numeroAvaliacoes] = n; numeroAvaliacoes++; return true; } } public String toString() { String retorno = "nome: "+nome+"\n"; for (int i = 0; i <= 3; i++) retorno += "nota: "+(i+1)+" : "+notas[i]+"\n"; return retorno; } } Altere este código para: • Calcular e retornar a média aritmética das provas; • O resultado final (“Aprovado”, “Prova Final” ou “Reprovado”), considerando os critérios adotados na faculdade; • Altere o método toString para retornar também estas informações. • Observe a classe Turma abaixo, analise o que ela faz e complete no código o que se pede. public class Turma{ private Aluno[] alunos; private int numeroAlunos; private int maximoTurma; public Turma(int max){ alunos= new Aluno[max]; numeroAlunos=0; maximoTurma=max; } public boolean adicionaAluno (Aluno aluno){ if(numeroAlunos> maximoTurma) return false; else{ alunos[numeroAlunos+1]=aluno; numeroAlunos++; return true; } } public Aluno getAluno(int posicao){ if(posicao==numeroAlunos) return null; else return alunos[posicao]; } public String getListaAlunos (){ String a=null; if(numeroAlunos==0) return null; else{ for(int i=0;i==numeroAlunos;i++){ a=""+alunos[i].getNome()+"\n"; } return a; } } public int pesquisa(String nome) { int posicao = -1; // coloque aqui o código para pesquisar e retornar a posição do aluno return posicao; } public void ordena() { // Coloque aqui o código para colocar o vetor alunos em ordem alfabética de nome. // Para comparar duas strings utilize o método compareTo que retorna um nº // menor que zero se a string que chama vem antes da comparada, 0 se são iguais // e um nº maior que zero caso a string seja maior. Exemplificando, // String nome = "Cleber"; e a expressão nome.compareTo("Ana"), retornará um // valor maior que zero. } } public float getMediaTurma(){ float soma=0; for(int i=1;i<=numeroAlunos; i++) soma=soma+alunos[i].getMedia(); return soma/numeroAlunos; } Processando argumentos da linha de comando Observe a classe abaixo. public class CalculadoraDeLinha { public static void main(String[] argumentos) { if (argumentos.length !=3) { System.out.println("Este programa precisa de 3 argumentos."); System.exit(1); } else { int primeiroValor = Integer.parseInt(argumentos[0]); char operador = argumentos[1].charAt(0); int segundoValor = Integer.parseInt(argumentos[2]); int resultado = 0; switch (operador) { case '+': resultado = primeiroValor + segundoValor; break; case '-': resultado = primeiroValor - segundoValor; break; case '*': resultado = primeiroValor * segundoValor; break; case '/': resultado = primeiroValor / segundoValor; break; } for (int indice=0;indice<argumentos.length;indice++) System.out.print(argumentos[indice]+" "); System.out.println("= "+resultado); } } } A próxima atividade trabalhará com métodos estáticos e as operações de pesquisa e ordenação em um conjunto de dados, neste casso, este conjunto de dados está em forma de vetor. A ordenação consiste em colocar os elementos considerados em determinada ordem. Consideraremos três algoritmos distintos de ordenação: troca, seleção e inserção. A ordenação por troca é o mais simples e o mais lento, conhecido também como método da bolha (bublle sort). As seguintes ações são executadas: • compara-se dois elementos; • se o elemento da esquerda for maior que o da direita, troque-os; • mova uma posição à direita; Os elementos ordenados ficam ao final do vetor. Método ordenaBolha na classe abaixo. A ordenação por seleção é relativamente simples, é mais rápida que a ordenação por troca, mais indicada quando o tempo de troca for significativo. O método consiste em: • percorrer o vetor e selecionar o menor elemento; • realizar uma troca, transferindo o menor para o início; Acumula os elementos ordenados no início do vetor. Método ordenaSelecao na classe abaixo. A ordenação por inserção também é relativamente simples, duas vezes mais rápida que a ordenação por troca e um pouco mais rápida que a ordenação por seleção. É mais indicada quando os elementos estão quase ordenados. O método consiste em: • copiar determinado elemento para um local temporário; • dirigir-se para a esquerda movendo os elementos para a direita; • seguir até encontrar a posição correta para o elemento. Acumula os elementos ordenados à esquerda. Método ordenaInsercao na classe abaixo. A pesquisa consiste em localizar um registro em um conjunto de elementos. Consideraremos dois algoritmos de pesquisa: pesquisa linear ou seqüencial e a pesquisa binária. Na pesquisa linear ou seqüencial consideraremos que não existe duplicação de elementos no conjunto. O método consiste em: • Percorrer o vetor da esquerda para a direita; • Comparar a chave pesquisada com cada elemento do vetor Se a chave pesquisada equivale ao elemento, retornar a posição do mesmo • Se o elemento não for encontrado retornar -1. É o método pesquisa na classe abaixo. Para a pesquisa binária temos que ter o conjunto de dados ordenado e sem duplicação de elementos. É mais eficiente que a pesquisa linear. O método consiste em: • Iniciar no meio do espaço de busca; • A cada comparação, elimina-se metade das possibilidades: o Se a chave é igual, o elemento foi encontrado. o Se a chave é maior, o elemento está à esquerda. o Se a chave é menor, o elemento está à direita. A implementação é o método pesquisa2 na classe abaixo. public class OrdenaPesquisa { public static void ordenaBolha(int[] vetor) { int n = vetor.length; for (int j = 0; j < n-1; j++) { for (int i = 0; i < n-1; i++){ if (vetor[i] > vetor[i+1]) { int temp = vetor[i]; vetor[i] = vetor[i+1]; vetor[i+1] = temp; } } } } public static void ordenaBolha(String[] vetor) { int n = vetor.length; for (int j = 0; j < n-1; j++) { for (int i = 0; i < n-1; i++){ if (vetor[i].compareTo(vetor[i+1]) > 0) { String temp = vetor[i]; vetor[i] = vetor[i+1]; vetor[i+1] = temp; } } } } public static void ordenaSelecao(int[] vetor){ int min; for(int i = 0; i < vetor.length; i++){ min = i; //posicao do vetor for(int j = i+1; j < vetor.length; j++){ if(vetor[j] < vetor[min]){ min = j; } } if(min != i){ int temp = vetor[i]; vetor[i] = vetor[min]; vetor[min] = temp; } } } public static void ordenaInsercao(int[] vetor) { int i, j, x; for (j = 1; j < vetor.length; j++) { x = vetor[j]; for (i = j-1; i >= 0 && vetor[i] > x; i--) vetor[i+1] = vetor[i]; vetor[i+1] = x; } } public static int pesquisa (int[] vetor, int x){ int posicao = -1; for (int i=0; i<vetor.length; i++){ if(vetor[i] == x){ posicao = i; } } return posicao; } public static int pesquisa2 (int[] vetor, int x){ int lo = 0; int hi = vetor.length; } while (lo<hi){ int i = (lo+hi)/2; if(vetor[i] == x){ return i; }else if (vetor [i] < x){ lo = i+1; }else{ hi = i; } } return -1; public static void main(String arg[]) { int[] dados = new int [] {45,23,78,35,15}; int[] dados2 = dados; ordenaInsercao(dados2); int p = pesquisa2(dados2,60); if (p != -1) System.out.println("Elemento encontrado na posição "+(p+1)); else System.out.println("Elemento não encontrado!"); ordenaInsercao(dados); for (int i = 0; i < 5; i++ ) { System.out.print(" : "+dados[i]); } } String [] pessoas = new String [] {"Suzana","Carlos","Ana","Gabriel","Ada"}; ordenaBolha(pessoas); for (int i = 0; i < 5; i++ ) { System.out.print(" : "+pessoas[i]); } } 10. Classes para manipulação de strings Cadeias de caracteres podem ser utilizadas para representação e processamento de qualquer informação textual, o que é frequentemente necessário para aplicações diversas, em especial envolvendo processamento de dados em arquivos e aplicações em rede. Java tem classes poderosas e flexíveis para o processamento de strings, cada uma com características especiais e métodos úteis, que serão apresentados neste capítulo. 10.1 A classe String Um conceito importante sobre strings é que instâncias dessa classe são compostas de zero ou mais caracteres (valores do tipo char) enfileirados em ordem de leitura (esquerda para a direita). O comprimento da string é dado pelo número de caracteres que ela contém. O índice de cada um dos caracteres indica a posição deste na string: este índice pode valer entre zero e o valor do comprimento da string menos um. Tentativas de acessar caracteres ou trechos de um string usando índices fora da faixa de valores válidos causarão uma exceção chamada java.lang.StringIndexOutOfBoundsException (exceções são mecanismos de Java de processamento de erros em tempo de execução). 10.1.1 Construindo instâncias Instâncias da classe String podem ser construídas diretamente, por atribuição direta a referências, sem necessidade da chamada do construtor através da palavra-chave new, esta é uma exceção entre as outras classes que vimos. Instâncias também podem ser construídas de forma mais tradicional, usando a palavra-chave new e um construtor que recebe como argumento uma outra instância, já existente, da classe String. 10.1.2 Métodos básicos da classe String Método length charAt equals equalsIgnoreCase startsWith endsWith Comentário Não tem argumentos e retorna o número contidos na string. Recebe como argumento um valor inteiro correspondente à posição do caracter que desejamos recuperar e retorna o caracter naquela posição. Método de comparação de strings que deve ser chamado a partir de uma instância da classe String e receber outra instância da classe String como argumento, e retornará o valor booleano true set todos os caracteres da instância que chamou o método forem iguais (inclusive a ordem e considerando maiúsculos e minúsculos) aos caracteres da instância passada como argumento. Ex.: String nome1 = “Carlos”; System.out.println(nome1.equals(“Carlos”)); // exibirá true System.out.println(nome1.equals(“carlos”)); //exibirá false Se comporta da mesma forma que equals, porém considera iguais caracteres maiúsculos e minúsculos. Este método retorna true se os primeiros caracteres da string que executar o método forem iguais aos caracateres da string passada como argumento. Ex.: String fabricante = “Nikon”; A expressão fabricante.startsWith(“Nik”) retornará true. Funciona como o método startsWith, porém compara somente os caracteres finais. Ex.: String ciência = “Metafísica”; A expressão ciência.endsWith(“física”) retornará true, mas ciência.endsWith(“Física”) retornará false. compareTo Compara duas strings e retorna um valor negativo caso a string que chamou esteja lexicograficamente antes da string passada como argumento, um valor positivo caso esteja depois e zero caso as duas strings sejam exatamente iguais. compareToIgnoreCase Funciona como o método compareTo, porém considera iguais caracteres maiúsculos e minúsculos. indexOf Recebe como argumento uma string e retorna a posição onde esta string aparece dentro da string que executou o método ou -1 se a string passada como argumento não estiver contida na que executou o método. Ex.: String dna = “CTAGGTGTAGGC”; String pedaço = “GG”; A expressão dna.indexOf(pedaço) retornará 3. toLowerCase Não recebe argumentos e retorna a string original com caracteres todos em caracteres minúsculos. toUpperCase Não recebe argumentos e retorna a string original com caracteres todos em caracteresmaiúsculos. trim Este método elimina os espaços (e caracateres de controle) no início e fim da string, retornando a string sem estes caracteres. Ex.: String texto = “ Andrade \n\n”; A expressão texto.trim() retornará “Andrade”. replace Recebe como argumento dois caracateres, e troca todas as ocorrências do primeiro caractere pelo segundo. Ex.: String gíria = “pé-de-meia”; A expressão gíria.replace(‘-‘,’ ‘) retornará “pé de meia”. substring Recebendo somente um valor inteiro como argumento , retornará a substring composta por todos os caracteres cujos índices sejam maiores ou iguais ao valor passado. Ex.: String aminoácido = “Fenilalanina”; A expressão aminoácido.substring(5) retornará “alanina”. substring Recebendo dois valores numéricos, retornará uma nova string composta por todos os caracteres cujos índices sejam maiores ou iguais ao primeiro argumento e menores do que o segundo argumento. Ex.: String aminoácido = “Fenilalanina”; A expressão aminoácido.substring(5,8) retornará “ala”. concat Recebe como argumento uma string e retorna a concatenação da string que executou o método com a passada como argumento. Ex.: String nome = “Mário”; A expressão nome.concat(“ de Andrade”) retornará “Mário de Andrade”. valueOf Método estático que converte valores de qualquer um dos tipos nativos, passados como argumentos, para uma string. parseInt Método da classe Integer que converte uma string em um valor do tipo int. Ex.; Integer.parseInt(“123”); retornará o inteiro 123. O mesmo vale para as outras classes Byte, Short, Long, Float e Double. Podemos executar métodos sobre resultados da chamada de outros métodos como: String curso = “ Sistemas de Informação ”; System.out.println(curso.trim().toUpperCase()); // exibirá SISTEMAS DE INFORMAÇÃO Note que a ordem e o aninhamento dos métodos da classe String em uma chamada em cascata é importante: “r”.toUpperCase().concat(“io de ”).concat(“j”.toUpperCase()).concat(“aneiro”) resultará “Rio de Janeiro”, enquanto “r”.toUpperCase().concat(“io de ”).concat(“j”).toUpperCase().concat(“aneiro”) resultará “RIO DE Janeiro”. 10.2 A classe StringBuffer 10.3 A classe StringTokenizer