Baixe o app para aproveitar ainda mais
Prévia do material em texto
Programação Orientada aProgramação Orientada a ObjetosObjetos AUTORIA Ricardo Bortolo Vieira Bem vindo(a)! Seja muito bem-vindo(a)! Olá prezado(a) aluno(a), este é o livro Programação Orientada a Objetos, sou o professor Ricardo Vieira, autor deste material, e o assunto que abordarei no decorrer do nosso estudo poderá contribuir com sua formação, especialmente a de desenvolvedor (a) de software. Além disso, este livro auxiliará em sua carreira e abrirá portas para o mundo dos negócios, mostrando-lhe as vantagens de trabalhar com programação. Meu objetivo, por meio deste livro, é ensiná-lo o paradigma Orientado a Objetos voltado a programação, e apresentar algumas técnicas que podem auxiliá-lo neste processo. Além disso, pretendo deixar claro que o uso correto desse paradigma poderá ajudá-lo a alcançar os objetivos estratégicos da organização onde trabalha ou auxiliá-lo a colocar em prática ideia, que por enquanto podem estar arquivadas e aguardando o momento certo para se tornarem grandes negócios. Este livro está organizado em quatro unidades, além da introdução e conclusão. Cada uma delas correspondendo a uma das partes importante na programação orientada a objetos. Na primeira unidade, você vai estudar o histórico e conceitos desse paradigma que nos permite programar de forma mais próxima do nosso pensamento. Além de estudar sobre a relação da programação orientada a objetos com a análise orientada a objetos, ou seja, estudando sobre classes, objetos, atributos e instâncias. Já na unidade II você poderá constatar os conceitos relacionados ao operador this, e outros operadores, os construtores para classes e algumas instruções de repetição. Depois, na unidade III, falaremos sobre comandos em geral para linguagens orientadas a objeto e aprendendo mais sobre construtores. Trataremos também sobre conceitos inerentes a Orientação a Objetos como Herança e Polimor�smo. Na unidade IV, vamos entender melhor sobre encapsulamento de propriedades e a forma correta de se utilizar um conceito muito poderoso chamado interface. Vamos tratar também sobre captura e tratamento de exceções e não poderíamos deixar de abordar a programação em um nível mais macro tratando sobre desenvolvimento em camadas. Agora, sem perder mais tempos, vamos direto a leitura! Tenha um bom aprendizado. Unidade 1 Programação orientada a objetos AUTORIA Ricardo Bortolo Vieira Introdução Caro (a) aluno (a), iniciaremos a primeira unidade do livro Programação Orientado a Objetos (POO) com uma breve introdução sobre o Paradigma Orientado a Objeto e a importância da elaboração de um código elegante dentro do projeto de produção de software. Em seguida, você verá como os conceitos de Classes e Objetos utilizando classes prede�nidas e suas bibliotecas da linguagem de programação Java, a utilização de estruturas dinâmicas como listas simplesmente ligadas/encadeadas. Nesta unidade, também você conhecerá e entenderá os conceitos e termos utilizados na análise e no projeto Orientado a Objetos (OO). Dentre os conceitos que veremos, estão o de tipos de dados abstratos, classe, instância, atributo, mensagem, , entre outros. Com esses conceitos iniciais, você terá uma visão geral sobre OO. Então, o que estamos esperando? Vamos ao trabalho? Boa leitura a todos. Paradigma da programação orientada a objetos AUTORIA Ricardo Bortolo Vieira A Orientação a Objetos (OO) surgiu de um trabalho acadêmico genial de Keith Tocher (1967) que formaliza a teoria da simulação no artigo intitulado The Art of Simulation. Ela foi baseada em modelos matemática e subdivida em três categorias: Discrete Events Simulation, Continuous Simulation e Monte Carlo Simulation. A categoria Discrete Events Simulation trabalha com mudanças de estado, relacionamentos e trocas de informações. Dessa forma, é fácil perceber que onde nossa OO surgiu (NANCE, 1995). À medida que os conceitos OO ganharam ampla aceitação durante as décadas de 1980 e 1990 surgiram muitas opiniões diferentes sobre as respostas corretas a essas perguntas, mas atualmente há uma visão coerente dos conceitos orientados a objeto. Esta introdução lhe proporcionará uma rápida visão do tópico e apresentará os conceitos básicos e a terminologia. (PRESSMAN, 2011). A principal característica do Paradigma Orientado a Objetos (POO) é uma maior e melhor expressividade das necessidades do nosso dia a dia. Possibilitando criar uma unidade de código mais próxima da forma como pensamos e agimos, assim facilitando o processo de transformação das necessidades diárias para uma linguagem orientada a objeto. Assim, Orientação a Objetos é um paradigma de análise, projeto e programação de sistemas de softwares baseado na composição e interação entre diversas unidades de software chamadas de objetos. Dá-se o nome de Programação Orientado a Objeto ao processo que utiliza uma linguagem OO. A sigla POO termina se fundindo entre a programação e o paradigma. A utilização de uma linguagem orientada a objeto somente, em alguns casos, não garante que se está programando efetivamente orientado a objeto. É importante prover um embasamento sobre os fundamentos da OO. Todo o conceito tem como �nalidade possibilitar e facilitar a aplicação destes conceitos. O uso correto destes conceitos eleva e facilita o processo de programação. O ponto de partida para a compreensão de OO é compreender o que é objeto e seus aspectos envolvidos em sua criação e sua manipulação (PRESSMAN, 2011). No mercado atual de softwares, grande linguagens de programação como Java, ASP.NET, CSharp, C++, Python são OO, assim você consegue perceber a importância de estudar e absorver os conceitos de OO. Neste livro iremos discutir o assunto de OO usando como base a linguagem JAVA. Métodos com Elegância Antes de conhecer a maneira apropriada de projetar um grande sistema de software Orientado a Objetos, inclusive a divisão adequada do sistema em classes com responsabilidades e colaborações convenientes, temos que entender o que torna uma classe individual elegante. Qual é o papel de uma classe? Que tipo de responsabilidades ela deve ter? Isto é, quais os dados ela deve manter e o que poderá ser feito com esses dados e com outros? Em outras palavras, qual deverá ser seu comportamento? Além disso, uma vez que tivermos tomado essa decisão, como iremos implementar esse comportamento com os métodos? Comecemos com os métodos. A elegância de um método está relacionada ao seu tipo de retorno, ao nome dos parâmetros ou ao corpo do método? Na verdade, está relacionada a todas essas partes. Para nos ajudar a entender as questões existentes em torno da elegância dos métodos, vamos considerar primeiro um exemplo simples. Suponhamos que estivéssemos desenvolvendo uma nova classe DataHolder que, quando solicitada, deverá inserir novos valores em um array de inteiros, referenciado por sua variável de instância privada data. Isto é, esse ato de inserção tem que fazer parte do comportamento da classe. Como resultado, temos de adicionar um ou mais métodos à classe para executar a inserção. Há vários métodos que poderíamos criar para dar à classe esse comportamento. Por exemplo, poderíamos criar um método insert( ) que use como parâmetro o novo valor inteiro a ser inserido e um índice inteiro indicando onde ele deverá ser inserido. O método apenas insere o valor no local apropriado do array data. A alternativa será dividir o processo em três métodos separados, em que o primeiro método, increaseCapacity( ), aumentará o array, se necessário. O segundo, shift( ), deslocará os outros inteiros para dar espaço para o novo inteiro. E o terceiro, put( ), deverá inserir o novo inteiro no local recém liberado. Além disso, poderíamos deixar para o usuário a chamada aos três métodos individualmente ou criar um método insert( ) adicional que chamasse esses outros três métodos. Também poderíamos usar um nome que não fosse "insert" para o método ou alterar a ordem ou o número de parâmetros. Por exemplo, poderíamos sobrecarregar o método para que dois valores pudessemser inseridos ao mesmo tempo. Também poderíamos ter vários tipos de retorno. O método poderia ter void como tipo de retorno ou, por exemplo, retornar informações indicando se foi bem sucedido na inserção do novo valor. Qual dessas opções seria a melhor? Voltaremos continuamente a esse exemplo nesta seção do capítulo e, no processo, responderemos a essa pergunta e a pergunta mais geral sobre o que torna um método elegante. Convenções de Nomenclatura Segundo Tucker (2009), vários princípios da criação de software podam nos ajudar a comparar e julgar as abordagens mencionadas no parágrafo anterior. Um princípio é usar nomes que revelem a �nalidade. Ele será examinado com mais detalhes porque não se aplica só aos métodos. Pode ser aplicado a qualquer parte do software que use nomes, inclusive métodos, variáveis, classes e interfaces. Um nome de método deve indicar a �nalidade do método, isto é, o que o método deverá fazer. O nome não deverá indicar como o método atingirá seu objetivo e sim qual será o objetivo. Um método que não retornar um valor (um método com tipo de retorno void) deverá ter um nome composto por um verbo ou um verbo e seu complemento, como print( ) ou setName( ). Nomes vagos como doIt( ) são inadequados. Um método que retornar um valor deverá ter um nome que re�ita o valor que estará sendo retornado, por exemplo, length( ) ou name( ). Esse tipo de método também poderia ter um verbo e seu complemento como nome. Como convenção pode-se utilizar a palavra "get" seguida do valor retornado. Por exemplo, um método que retorne o tamanho de alguma estrutura de dados poderia receber o nome size( ) ou getSize( ). Com relação ao nosso exemplo DataHolder, o nome insert( ) será satisfatório, pois descreverá sucintamente o que o método deverá fazer. Classes e interfaces deverão ter nomes que re�itam o papel ou a �nalidade de objetos desses tipos. O nome de uma classe será a primeira pista que o leitor tem do papel real que ela desempenha em um projeto e portanto, vale a pena dedicar algum tempo na busca de um nome apropriado. Normalmente os nomes de classes são substantivos, como Date ou ComputerCard. Quase sempre interfaces têm nomes que terminam em "-able", como Cloneable ou Iterable (TUCKER, 2009). Para concluir, as variáveis têm que ser nomeadas apropriadamente para melhorar a legibilidade. Considere um programa com uma variável chamada nT. Um argumento a favor de um nome assim seria que ele é curto e, portanto, economiza tempo de digitação e ajuda a encurtar as linhas de código. Contudo, o nome não é signi�cativo no que diz respeito a indicar a função da variável e o leitor é forçado a memorizá-la. Por outro lado, chamar a variável de numberOfThreads ou NumThreads ou até mesmo numThrds em vez de nT, aumenta drasticamente a facilidade de entender o código. Uma variável boolean deverá ter um nome apropriado para o valor que representa. Geralmente não deverá representar a negação de um valor, então, por exemplo, não deveremos chamar nossa variável de notYetDone, que poderia resultar na necessidade de expressões como a negativa dupla !notYetDone. Em vez disso, seria melhor chamá-la de done e usar a expressão !done sempre que notYetDone tivesse de ser usada. É claro que o nome done também não é ideal, já que a palavra não contém informações su�cientes para ajudar o leitor a entender o papel da variável. O nome da variável deverá informar que atividade é ou não executada. Por exemplo, se essa variável estiver sendo usada para indicar que uma imagem grá�ca acabou de ser carregada e já pode ser vista, um nome melhor seria doneLoading. Lembrem-se, nomes ruins não levam apenas a enganos; eles tornam o sistema inteiro mais difícil de entender, o que vai contra nosso desejo de ter um software legível conforme trata Tucker (2009) em seu livro de princípios e paradigmas. Métodos Coesos Ainda conforme Tucker(2009), outro princípio da criação de softwares é: "os métodos devem fazer apenas uma coisa e fazê-la bem". Isto é, um método não deve executar duas ou mais tarefas a menos que façam parte de uma mesma ação coesa. Por exemplo, faz sentido o método insert( ) mencionado acima aumentar o array, mover os outros valores para dar espaço para o novo valor e adicionar o novo valor, porque tudo isso faz parte de uma ação coesa. Por outro lado, um método que tanto insira novos itens em um array data quanto determine se uma String está na forma de um endereço de e-mail não é coeso. A principal razão para evitar a criação desse tipo de método é que, com frequência, queremos executar uma das ações, mas não as duas. Nesse caso, um método que execute as duas é desnecessário. Um método é muito mais reutilizável quando faz apenas uma coisa. Na Figura 01 está um exemplo de um método não coeso. Esse método está claramente tentando fazer duas coisas e usando o �ag para determinar qual delas fazer. Seria melhor termos dois métodos auxiliares separados, como doThis( ) e doThat( ), nenhum deles precisando de um �ag. Uma vez que tivermos esses métodos, poderemos reescrever o método acima conforme a Figura 02. Agora esse código será aceitável (exceto pelos nomes �ag, this e that, que não revelam a �nalidade), já que o método está apenas agindo como uma central de despachos e, portanto, está fazendo apenas uma coisa e fazendo-a bem. Figura 1 - Exemplo de método não coeso. Elaborado pelo autor. Fonte: elaborado pelo autor. Figura 2 - Exemplo de método coeso. Fonte: elaborado pelo autor. Um resultado interessante para o princípio da coesão, tratado por Tucker(2009), é o princípio que um método deverá modi�car o estado de um objeto ou de objetos existentes ou retornar um valor, mas não ambos. Com estado de um objeto, queremos dizer os valores de suas variáveis de instância. Novamente, o raciocínio por trás desse princípio é o de que, às vezes, podemos querer modi�car o estado de um objeto, mas não retornar um valor, em outras palavras, pode querer retornar um valor, mas não modi�car um objeto. Logo, a título de reutilização, é melhor separar essas ações em dois métodos separados. Observe que a adesão rigorosa a esse princípio requer que não haja modi�cação de código dentro de métodos que retornem valores. Por exemplo, um método que informa se um array está classi�cado ou revele qual o maior valor do array retorna um valor e, portanto, não deve modi�car o array. Outra maneira de formular esse princípio seria dizendo que métodos que retornam valores não devem ter efeitos colaterais, e métodos com efeitos colaterais não devem retornar valores. Dito isso, observe que temos usado as terminologias "diretrizes" e "princípios" em vez de "regras". Ou seja, essas diretrizes devem ser levadas em consideração no projeto ou implementação de um sistema de software, mas não são regras a serem rigidamente seguidas conforme descreve Tucker (2009). Em algumas situações, pode ser melhor para o projeto se ignorarmos um ou mais desses princípios. E alguns códigos legados e de biblioteca não os seguem. Por exemplo, o pacote java.util tem uma classe Stack com um método pop( ) que tanto remove o objeto do topo da pilha quanto o retorna. Tecnicamente, esse comportamento desobedece ao princípio mencionado acima, mas é aceitável porque é um comportamento sensato nesse caso e, o mais importante, porque esse método vem sendo usado há anos e alterar seu comportamento agora seria muito pior do que deixar que ele continue desobedecendo à diretriz. Objetos Bem Formados Aqui, ainda citando Tucker(2009), está outro princípio relativo a métodos elegantes: "um método não privado deverá manter um objeto em um estado bem formado". Por exemplo, suponhamos que você tivesse uma classe com duas variáveis de instância: um array de inteiros data e um inteiro max, que armazenam o valor máximo do array data. Você deverá tomar cuidado para não ter métodos na classe que modi�quem o array sem atualizar também a variável max. É a esse tipo de coerência interna que nos referimos quando dizemos que uma classe é "bem formada". Como formular os requisitos decoerência dos objetos de uma classe? Isto é, como saber se a instância de uma classe está bem formada? Uma boa maneira é criar uma lista das invariantes da classe. Uma invariante de classe é uma declaração que fornece os requisitos sobre o estado de instâncias da classe entre chamadas de método públicas. Um exemplo de invariante de classe é a declaração "O valor de max e o maior valor do array data deverão ser iguais". Como outro exemplo, considere a implementação, apresentada na Figura 03, da classe DataHolder discutida anteriormente. Objetos Bem Formados Observe que o array data está sempre repleto de dados que foram inseridos. Isto é, nunca haverá locais não usados no array. Essa é uma invariante para objetos da classe DataHolder. Se a invariante for rompida, poderá ocorrer um comportamento inesperado. Para evitar isso, os três métodos auxiliares increaseCapacity( ), shift( ) e put( ) foram construídos como privados. Como resultado, os objetos desta classe, poderão �car temporariamente mal formados. Por exemplo, após increaseCapacity( ) ter sido chamado, mas serão restaurados para um estado bem formado, antes de Figura 3 - Implementação da Classe DataHolder Fonte: elaborado pelo autor. algum método público retornar. Se increaseCapacity( ) ou shift( ) fossem públicos, qualquer usuário do objeto poderia chamá-los isoladamente, causando a má formação do objeto. Para que as invariantes de classe sejam mantidas, é preciso que as variáveis de instâncias sejam privadas ou �nais, se tiverem envolvimento com alguma invariante de classe. Caso contrário, outro objeto poderia acidental ou maliciosamente alterar o valor da variável e gerar o objeto mal formado. Tipo Abstrato de Dados Serra (2003) apresenta a noção de Tipo Abstrato de Dados (TAD), iniciando pela especi�cação de um tipo de dado com as suas propriedades fundamentais, de maneira independente da implementação da linguagem utilizada. São três passos envolvidos para implementar um tipo abstrato de dados (TAD): O primeiro passo será a de�nição de uma API Java (Application Programming Interface), ou simplesmente interface, que descreverá os métodos que o TAD suportará e como eles serão declarados e como serão utilizados. O segundo passo será a escolha da representação Concreta do TAD que será utilizada na implementação. Assim, basicamente dois tipos de representação são introduzidos: ○ Estrutura Estática (com a utilização de arrays); ○ Estrutura Dinâmica (com a utilização de listas ligadas/encadeadas, pilhas, árvore, etc.). E o terceiro passo será a implementação da interface através de uma classe e levando em consideração a representação escolhida no segundo passo. Poderá existir muitas implementações para todo o TAD, contudo todas as implementações deverão respeitar a interface de�nida, conforme trata Serra (2003). Estruturas Segundo Serra(2003), precisamos frequentemente agrupar vários elementos e ou dados num conjunto. A princípio não saberemos o número exato de elementos que serão agrupados. A cada instante podemos remover ou acrescentar elementos ao conjunto. Dentro da programação deveremos considerar dois tipos de estruturas que permitirão guardar uma coleção de elementos, que poderão ser a Estrutura Estática e a Estrutura Dinâmica. Os elementos poderão ser organizados de maneira distinta. Poderemos destacar, entre as organizações possíveis: Estrutura Linear: Determina que haja entre os elementos da coleção, a existência de uma determinada ordem. Por exemplo: Primeiro elemento, Segundo elemento, ... N elemento, Último elemento. Estrutura Hierárquica: É a organização de elementos que poderão ser representadas em forma de árvore. Estrutura Grafo: É a organização de elementos que serão representadas em forma de rede. Neste capítulo serão apresentados exemplos de implementações destas três estruturas: Linear, Estática e Dinâmica. Começaremos pela Figura 04 apresentando uma estrutura linear. Estrutura Estática Ainda segundo Serra(2003), a principal característica da estrutura estática é possuir um espaço alocado e permanecerá inalterável até antes da sua utilização. Esta estrutura não deverá conter mais elementos do que foi inicialmente pré- determinado. A Estrutura Estática será representada através do uso de tabelas, em termos da linguagem de programação Java. Uma vez alocado um determinado espaço numa tabela, este permanecerá inalterável, independente das operações de de remoção e inserção dos elementos, mesmo que esta estrutura não possua nenhum elemento armazenado nela. Figura 4 - Representação da estrutura linear Fonte: elaborado pelo autor. Para facilitar a compreensão de vocês, meus caros leitores, será apresentado uma implementação, na Figura 05, de uma interface denominada estruturaLinear por meio de uma determinada classe chamada ArrayCircularList. Esta implementação está baseada na utilização de uma Estrutura Estática, que servirá para guardar os elementos de uma determinada coleção. A opção foi a utilização de uma estrutura circular. Estrutura Dinâmica Continuando a referência segundo Serra (2003), Uma das principais características da estrutura dinâmica é que ela poderá sofrer alterações à medida que ocorrer a sua manipulação através de inserção e remoção de elementos em sua estrutura. A Estrutura Dinâmica, em sua dimensão, não possuirá limitações, com exceção da limitação física do espaço de memória do computador, sendo esta a sua única restrição, onde ocorrerá a execução do algoritmo. A Estrutura Dinâmica será instanciada com a utilização do tipo de dado que ela �zer a Referencia (apontador). As Estruturas Dinâmicas poderão ser criadas para fazer a representação das coleções dos elementos com diferentes tipos de organização. A implementação de uma Estrutura Linear poderá ser realizada com a utilização de Estruturas Dinâmicas, com a representação de listas simplesmente ligadas, de listas duplamente ligadas, de listas circulares, etc. Será apresentado na Figura 06, a implementação de uma interface denominada estruturaLinear, como um exemplo de utilização destas listas. Listas simplesmente ligadas/encadeadas A forma mais simples para a representação de uma coleção de elementos será a utilização de uma lista encadeada, que juntos formarão uma ordenação linear, conforme trata Serra (2003). O objeto da classe No fará a representação de cada Figura 5 - Exemplo de implementação uma estrutura estática Fonte: elaborado pelo autor. elemento da coleção. A ordenação será determinada com o armazenamento da referência em um nó para um elemento e uma referência, será chamada de próximo, para o próximo nó da coleção. Conforme será visto na Figura 06. Figura 6 - Representação de Lista Encadeada. Cabeça Próximo Próximo Próximo Cauda Roma Seatle Toronto Elemento Elemento Elemento Null Fonte: baseado em Serra (2003). Serra (2003) indica que poderá ser vista como uma ligação ou apontador para outro nó a referência Próximo dentro de um nó. Serão chamados, respectivamente, de Cabeça e Cauda da lista o primeiro Elemento (nó) e os últimos Elementos (nós) de uma lista. A cauda será o Elemento (nó) que terá a referência Próximo igual à null, indicando o �m da lista. O deslocamento de um Elemento (nó) para outro seguindo a referência Próximo será conhecido como percorrer a lista ou caminhar na lista. Será conhecida como uma lista simplesmente encadeada, uma lista encadeada que for de�nida desta maneira. Uma lista simplesmente encadeada, diferentemente de uma tabela, não terá tamanho �xo pré-determinado e alocará ao número de Elementos, os espaços proporcionais a cada um deles. Na Figura 07, será de�nida uma classe No, para implementação de uma lista simplesmente encadeada na linguagem de programação Java. A interface estruturaLinear pode ser implementada usando uma lista simplesmente encadeada na classe ListaEncadeada conforme mostra a Figura 08. Figura 7 - Implementação de uma Lista Encadeada em Java Fonte: elaborado pelo autor. Inserir Elemento na Cabeça da Lista Numa listasimplesmente encadeada podemos inserir ou remover um elemento na cabeça da lista. Conforme ilustra a sequência de Figuras de 09 a 11. Figura 9 - Antes da inserção de novo nó na Cabeça da Lista Cabeça Cauda Roma Seatle Toronto Fonte: baseado em Serra (2003). Figura 8 - Implementação de uma Lista Simplesmente Encadeada Fonte: elaborado pelo autor. Figura 11 - Depois da inserção de novo nó Cabeça da Lista Cabeça Cauda Roma Seatle TorontoBaltimore Fonte: baseado em Serra (2003). O código para esta operação é descrito na Figura 12. Figura 12 - Código para a inserção de novo nó na Cabeça da Lista Fonte: elaborado pelo autor. Inserir Elemento na Cauda da Lista Nesta situação Serra (2003) indica que teremos que percorrer todos os elementos a partir do ponteiro da cabeça até chegar no último Elemento, caso não tenha a referencia para o último Elemento da lista (ponteiro Cauda). A representação escolhida para a lista, como nosso exemplo, possui uma variável com a referência para o último Elemento (Cauda). Esta operação será descrita nas Figuras de 13 a 15. Figura 13 - Antes da inserção de novo nó na Cauda da Lista. Cabeça Cauda Roma Seatle TorontoBaltimore Fonte: baseado em Serra (2003). Figura 14 - Inserção de novo nó na Cauda da Lista. Cabeça Cauda Roma Seatle Toronto Zurich Fonte: baseado em Serra (2003). Figura 15 - Depois da inserção de novo nó Cauda da Lista. ZurichRoma Seatle Toronto Cabeça Cauda Fonte: baseado em Serra (2003). O código para esta operação é apresentada na Figura 16. Remoção do Nó Serra (2003) trata essa situação da seguinte forma - o elemento (nó) da cabeça ou da Cauda da lista poderá ser removido. A implementação do método seguinte permitirá remover o Elemento da Cabeça da lista. Para a remoção do Elemento da cauda da lista, obrigatoriamente deverá percorrer cada Elementos da lista, desde a cabeça até ao penúltimo elemento da lista. Figura 16 - Código para a inserção de novo nó na Cauda da Lista. Fonte: elaborado pelo autor. Figura 17 - Método para a remoção do elemento da Cabeça da Lista. Fonte: elaborado pelo autor. Listas Duplamente Encadeada/Ligadas Deverá existir para cada Elemento (nó) da lista duplamente encadeada, uma ligação não somente para o próximo Elemento, mas também para o Elemento anterior da lista. Com esta variante, da lista simplesmente encadeada, permitirá a inserção e a remoção o Elemento (nó) na cabeça e na cauda da lista. Para implementação deste tipo de lista, Devemos especi�car a classe NoD, composta por Elemento (nó) referência para o Elemento (nó) seguinte e referência para o Elemento (nó) anterior. Estes são os passos descritos por Serra (2003) para o tratamento de lista duplamente encadeadas. Além disso, o código desta classe poderá ser visualizado na Figura 18. Figura 18 - Método para a remoção do elemento da Cauda da Lista. Fonte: elaborado pelo autor. Assim o código para lista dupla é apresentado nas Figuras 19, 20 e 21. Figura 19 - Método para inserção e a remoção de elementos da Lista Simplesmente Encadeada. Fonte: elaborado pelo autor. Figura 20 - Método para inserção e a remoção de elementos da Lista Duplamente Encadeada. Fonte: elaborado pelo autor. Figura 21 - Método para inserção e a remoção de elementos da Lista Duplamente Encadeada. Fonte: elaborado pelo autor. Figura 22 - Método para inserção e a remoção de elementos da Lista Duplamente Encadeada. Fonte: elaborado pelo autor. Classes e objetos AUTORIA Ricardo Bortolo Vieira Classes Prede�nidas Conforme apresenta Sierra (2012), os nomes dos pacotes da linguagem de programação Java sempre começarão com Java, para pacotes do núcleo da linguagem ou Javax para as extensões ao núcleo. Será utilizada a instrução de import para identi�car e carregar as classes que precisarmos utilizar em nossas implementações. Sempre antes da de�nição das classes é que as instruções import deverão aparecer. Exemplo: import java.util.Scanner;. Na linguagem de programação Java, as classes prede�nidas serão agrupadas em categorias de classes conhecidas como pacotes (package), também são chamadas de bibliotecas de classes Java ou são chamadas ainda de Interface de Programação de Aplicativos Java (Java API). Na linguagem de programação Java, a Biblioteca (API – Application Programming Interface), ela será composta por um conjunto de classes do JDK, que são organizadas em pacotes; São exemplos de pacotes Java apresentados por Sierra (2012): java.util: Contém a estrutura de coleções, classes de coleção herdadas, modelo de evento, facilidades de data e hora, internacionalização e classes de utilidade diversas (um tokenizer de string, um gerador de números aleatórios e uma matriz de bits). java.net: Fornece as classes para implementar aplicativos de rede (sockets e URLs); java.lang: Fornece classes que são fundamentais para o design da linguagem de programação Java. Tipos e funcionalidades básicas da linguagem. Incluindo entre outras, as classes String, Math, Integer e Thread. Ela será importada automaticamente em seus programas Java; java.io: Fornece entrada e saída do sistema através de �uxos de dados, serialização e sistema de arquivos. São classes para escrita e leitura em arquivos; java.awt: Contém todas as classes para criar interfaces com o usuário e pintar grá�cos e imagens. São componentes grá�cos originalmente da linguagem de programação Java (Abstract Window Toolkit); java.applet: Fornece as classes necessárias para criar um applet e as classes que um applet usa para se comunicar com seu contexto de applet. São classes especí�cas para tratamento de applets; java.swing: Fornece um conjunto de componentes "leves" (a toda linguagem Java) que, no grau máximo possível, funcionam da mesma maneira em todas as plataformas. É um framework da plataforma Java para melhoramentos à biblioteca AWT; (Fonte: https://docs.oracle.com/javase/8/docs/api/overview- summary.html). Biblioteca java.lang Schildt (2013) trata sobre a biblioteca java.lang como sendo importada automaticamente para todos os programas. Ela contém classes e interfaces que são fundamentais para praticamente toda a programação Java. É o pacote Java mais amplamente usado e todos os programadores de Java devem ter um conhecimento geral do que ele fornece. O pacote java.lang inclui as classes de nível superior apresentadas no Quadro 01. As interfaces de nível superior de�nidas por java.lang são as mostradas no Quadro 02. Tabela 1 - Pacote java.lang. Pacote java.lang Boolean Byte Character Class ClassLoader ClassValue Compiller Double Enum Float InheritableThreadLocal Ingeter Long Math Number Object Package Process ProcessBuilder Runtime RuntimePermission SecurityManager Short StackTraceElement StrictMath String StringBuffer StringBuilder System Thread ThreadGroup ThreadLocal Throwable Void Fonte: elaborado pelo autor. Como podemos ver, as classes e interfaces de java.lang de�nem um grande número de funcionalidades. Nem todas as partes são amplamente usadas, ou usadas por todos os programadores. Por exemplo, algumas classes, como StrictMath e Compiler, são mais aplicáveis a situações especí�cas. Bibliotecas AWT e Swing Segundo Pereira (2017), será fornecido pela biblioteca AWT todas as classes para a criação de interfaces com o usuários, imagens e pintará grá�cos. Ela é uma interface grá�ca de usuário ( Graphical User Interface - GUI). Ela delegará para a Interface Grá�ca de Usuário (GUI) da plataforma nativa (Windows, Linux, Mac) a criação, estilo e comportamento. Com o seu lema "Write once, run anywhere" ("Escreva uma vez, execute em qualquer lugar"), o estilo será o mesmo da plataforma, se �zermos uma caixa de texto, por exemplo, no Windows ou Linux, que atenderá à promessa de portabilidade do Java, conforme apresenta Schildt (2013). Para aplicações simples, o sistema funciona perfeitamente. O problema será para as aplicações mais complexas, as mudanças sutis nos comportamentos de Text�elds, scrolls ou menus poderão causar alterações naexperiência do usuário e até causar problemas diferentes em cada sistema, acabando com a ideia de portabilidade. Com o pacote "java.awt", biblioteca AWT foi introduzida no Java 1.0. Logo depois, como uma extensão, é que a biblioteca Swing foi introduzida na versão do Java 1.1 e também como parte do pacote padrão na versão do Java 1.2, dentro do pacote "javax.swing". A biblioteca Swing não delegará a criação, estilo e comportamento da interface grá�ca de usuário (GUI) para a plataforma nativa, mas ela tomará para si este trabalho, cumprindo o objetivo de portabilidade. Tabela 2 - Interfaces de nível superior de�nidas por java.lang Appendable Cloneable Readable Class ClassLoader ClassValue AutoCloseable Comparable Runnable CharSequence Iterable Fonte: elaborado pelo autor. A biblioteca Swing é uma biblioteca que complementa o pacote AWT. No exemplo da Figura 22, as classes terão pelo menos três linhas com a diretiva import apontando para pacotes de classes externas, conforme as declarações seguintes: import java.awt.*; => permite a utilização de diversas classes do pacote awt, além de possuir uma série de constantes numéricas. import java.awt.event.*; => usado para o processamento dos eventos que ocorrem na janela, tais como clique do mouse. import javax.swing.*; => permite a utilização de diversas classes do pacote swing. Biblioteca java.applet Figura 22 - A sequência dos exemplos import java.awt.*; import java.awt.event.*; import java.awt.event.*; import javax.swing.*; Fonte: elaborado pelo autor. “Os applets diferem dos tipos de programa mostrados nos exemplos anteriores. Eles são programas pequenos projetados para transmissão pela Internet e serem executados dentro de um navegador. Já que a máquina virtual Java se encarrega da execução de todos os programas Java, inclusive applets, oferecem uma maneira segura de baixar e executar dinamicamente programas pela Web.”( SCHILDT, 2015, p.499). Há dois tipos gerais de applets: os baseados apenas no Abstract Window Toolkit (AWT) e os baseados em Swing. Ambos dão suporte à criação de uma interface grá�ca de usuário (GUI). AWT é o kit de ferramentas de GUI original e Swing é a alternativa leve e moderna de Java. Segue um exemplo de um Applet simples apresentada na Figura 23. Biblioteca java.net: Ainda conforme Schildt (2013), java foi projetada para atender às necessidades do ambiente de programação da Internet. Portanto, não deve surpreender o fato que a linguagem dá amplo suporte à rede em sua biblioteca de APIs. O principal pacote de rede de Java é o java.net. Ele fornece classes que permitem que um aplicativo acesse recursos de rede de maneira conveniente e e�caz. É necessário enfatizar que rede é um assunto avançado. Além disso, é um assunto muito extenso e, às vezes, complexo. Uma discussão sobre rede pode facilmente envolver vários outros tópicos, como detalhes relacionados a protocolos e à arquitetura geral da Internet, que não fazem parte do escopo deste livro. O conceito básico do suporte Java ao uso de rede é o soquete. Um soquete identi�ca uma extremidade em uma rede. Ele é à base das redes, porque permite que um único computador atenda muitos clientes diferentes ao mesmo tempo e Figura 23 - Exemplo de um Applet simples baseado em AWT Fonte: elaborado pelo autor. forneça vários tipos de informações diferentes. Isso é feito com o uso de uma porta, que é um soquete numerado em uma máquina especí�ca. Diz-se que um processo de servidor está "escutando" uma porta até um cliente se conectar a ela. Um servidor pode aceitar vários clientes conectados ao mesmo número de porta, mas cada sessão é exclusiva. SAIBA MAIS QUALIFICAÇÃO DE SOFTWARES Como pode ser quali�cado um software? É muito simples de�nir isso pelo tempo de desenvolvimento ou pela excelência na programação. Existem casos de desenvolvimento de softwares em que o analista ouve todas as informações e apresenta uma solução, quase que "surreal". Algo que poderá resolve perfeitamente o que foi solicitado. Olhando assim, a sensação que temos parece que o atendimento foi excepcional, contudo, na maioria das vezes, os programas feitos neste formato não atendem a real necessidade dos clientes. Não devemos julgar o cliente por não apresentar de forma assertiva as suas necessidades. E a consequência disso tudo é a perda de investimento �nanceiro e de tempo em um projeto que não vai atender as suas necessidades. Casos assim são muito comuns de acontecer, é muito provável que você já tenha vivenciado ou ouvido falar sobre isso. Esse tipo de problema não é exclusivo do desenvolvimento de softwares, é algo que ocorre com frequência no mercado, em geral. Para provar isso, basta surgir a necessidade de um serviço, em sua casa ou trabalho, em que não tenha nenhum conhecimento do processo, como consertar uma porta, uma janela ou uma in�ltração na parede. A solução só vem quando um pro�ssional quali�cado está mais preocupado em satisfazer o cliente do que resolver exclusivamente o problema apresentado. Os pro�ssionais que mantêm esse tipo de procedimento de atendimento vão sendo substituídos aos poucos. Na rotina diária de um programador, normalmente, o início do projeto vem de um conversa informal e só lá na primeira apresentação, depois de um grande tempo de dedicação, é que o cliente consegue esclarecer ainda de forma abstrata com frases como "não é bem isso que eu queria". Outro caso comum que acontece, pela falta de alinhamento, são as solicitações do cliente, ir aumentando durante o processo de desenvolvimento e como nada está estabelecido de forma clara no início do trabalho, você poderá até prolongar o projeto, mas, possivelmente, não atenderá todas as necessidades do seu cliente. Lembrando que cliente não tem obrigação de entender de programação e que a preocupação deverá ser do programador, de atender o cliente e não o contrário. Um bom pro�ssional deve fazer uso de uma excelente interpretação às necessidades do cliente e oferecer não o que ele está pedindo, mas sim o que realmente vai suprir sua necessidade. Biblioteca java.io Conforme Silveira (2006), a parte que controlará a entrada e saída de dados, conhecido como io, da mesma maneira como em todas as bibliotecas em Java, será também orientada a objetos. Ela usará os principais conceitos de utilização de interfaces, de polimor�smo e das classes abstratas. A idéia atrás da utilização do polimor�smo no pacote java.io, será a utilização para toda e qualquer operação de �uxos de entrada (InputStream) e de saída (OutputStream), referente a um arquivo, a uma conexão remota via soquete, a um campo blob do banco de dados, ou até mesmo às entrada e saída padrão de um programa , normalmente os teclados e os consoles. Na linguagem de programação Java as classes abstratas InputStream e OutputStream de�nirão, respectivamente, o padrão de comportamento dos �uxos. Será possível ler bytes em um �uxo de entrada e escrever bytes no �uxo de saída. Pode ser exibida a grande vantagem dessa abstração, em um método qualquer que implemente uma classe OutputStream, que receberá como argumento para escrever um �uxo de saída. O método está escrevendo onde? Não será necessário saber e isso também não importará, porque quando o sistema realmente precisar escrever em um arquivo ou em um soquete, bastará chamar esse mesmo método, já que ele aceitará qualquer classe "�lha" de OutputStream. Biblioteca java.util: o pacote java.util de�ne classes e interfaces que atendem várias tarefas comumente encontradas quando se programa. Por exemplo, ele contém o Collections Framework. O Collections Framework é um dos subsistemas mais poderosos do Java e dá suporte a uma so�sticada hierarquia de interfaces e classes que gerenciam grupos de objetos. O pacote java.util também fornece várias classes utilitárias, inclusive as que formatam dados para saída, leem dados formatados e trabalham com data e hora. Como java.util dá suporte a um conjunto tão amplo de funcionalidades, é um pacote muito extenso. O pacote java.utilé muito grande, mas seu tamanho é gerenciável porque as classes e interfaces que compõem o Collections Framework podem ser examinadas separadamente, como um grupo. Fonte: o autor. O uso de atributos AUTORIA Ricardo Bortolo Vieira Os atributos são pertencentes à classe, eles podem ser do tipo primitivo ou referência (objetos), os seus modi�cadores podem ser: public, private, protected ou default. O ciclo de vida destes atributos está vinculado ao ciclo de vida da classe. Um carro, além de ter a capacidade de realizar tarefas, também tem atributos, como cor, número de portas, quantidade de gasolina no tanque, velocidade atual e registro dos quilômetros totais dirigidos (isto é, a leitura do odômetro). Assim como suas capacidades, os atributos do carro são representados como parte do seu projeto nos diagramas de engenharia (que, por exemplo, incluem um odômetro e um medidor de combustível). Ao dirigir um carro real, esses atributos são incorporados a ele. Cada carro mantém seus próprios atributos. Cada carro sabe a quantidade de gasolina que há no seu tanque, mas desconhece quanto há no tanque de outros carros. Um objeto, da mesma forma, tem atributos que ele incorpora à medida que é usado em um programa. Esses atributos são especi�cados como parte da classe do objeto. Por exemplo, um objeto conta bancária tem um atributo saldo que representa a quantidade de dinheiro disponível. Cada objeto conta bancária sabe o saldo que ele representa, mas não os saldos de outras contas bancárias. Os atributos são especi�cados pelas variáveis de instância da classe. No encapsulamento, as classes e seus objetos encapsulam, isto é, contêm seus atributos e métodos. Os atributos e métodos de uma classe (e de seu objeto) estão intimamente relacionados. Os objetos podem se comunicar entre si, mas eles em geral não sabem como outros objetos são implementados, os detalhes de implementação permanecem ocultos dentro dos próprios objetos. Continuando com Atributos As variáveis do tipo atributo, diferentemente das variáveis temporárias (declaradas dentro de um método), recebem um valor padrão. No caso numérico, pode ser zero, no caso de boolean, pode ser false. Você também pode dar valores default, como apresentado na Figura 24. Nesse caso, quando você criar uma conta, seus atributos já estão "populados" com esses valores colocados. Imagine que comecemos a aumentar nossa classe Conta e adicionar nome, sobrenome e CPF do cliente dono da conta. Teríamos muitos atributos. E se você pensar bem, uma Conta não tem nome, nem sobrenome nem CPF, quem tem esses atributos é um Cliente. Então podemos criar uma nova classe e fazer uma composição. Seus atributos também podem ser referências para outras classes. Suponha as seguintes classes Cliente e Conta apresentado nas Figuras 25 e 26. Figura 24 - Continuando com Atributos Fonte: elaborado pelo autor. Figura 25 - Exemplo de atributos da classe Cliente Fonte: elaborado pelo autor. E dentro do main da classe de teste como mostra a Figura 27. Aqui, simplesmente houve uma atribuição. O valor da variável c é copiado para o atributo titular do objeto ao qual minhaConta se refere. Em outras palavras, minhaConta tem uma referência ao mesmo Cliente que c se refere, e pode ser acessado através de minhaConta.titular. Você pode realmente navegar sobre toda essa estrutura de informação, sempre usando o ponto: Cliente clienteDaMinhaConta = minhaConta.titular; clienteDaMinhaConta.nome = "Luke"; Ou ainda, pode fazer isso de uma forma mais direta e até mais elegante: minhaConta.titular.nome = "Luke"; Figura 26 - Exemplo de referência de atributos da classe Conta. Fonte: elaborado pelo autor. Figura 27 - Exemplo de referência de atributos dentro do main da classe de teste. Fonte: elaborado pelo autor. Um sistema orientado a objetos é um grande conjunto de classes que vai se comunicar, delegando responsabilidades para quem for mais apto a realizar determinada tarefa. A classe Banco usa a classe Conta que usa a classe Cliente, que usa a classe Endereco. Dizemos que esses objetos colaboram, trocando mensagens entre si. Por isso acabamos tendo muitas classes em nosso sistema e elas costumam ter um tamanho relativamente curto. Instanciação referência para objetos AUTORIA Ricardo Bortolo Vieira No contexto de uma atribuição, e conforme Deitel (2008), o operador new tem esta forma geral: var_classe = new nome_classe(lista_arg); O operador new é o responsável pelo processo de instanciação do objeto, representando uma forma extremamente simples de atribuir valores default a um objeto. A declaração: Televisor tv = new Televisor(); pode ser lida como: construa o objeto tv (do tipo Televisor) com valores default. Como o próprio nome diz, o método construtor é o responsável por construir um objeto com determinados valores. Se uma classe não de�nir seu próprio construtor, new usará o construtor padrão fornecido por Java. Logo, new poderá ser usado para criar um objeto de qualquer tipo de classe. O operador new retornará uma referência ao objeto recém-criado, que (nesse caso) será atribuído a var-classe. Já que a memória é �nita, e conforme Deitel (2008), é possível que new não consiga alocar memória para um objeto por não existir memória su�ciente. Se isso ocorrer, haverá uma exceção de tempo de execução. Para os exemplos de programa deste livro, não precisamos nos preocupar em �car sem memória, mas temos que considerar essa possibilidade em programas do mundo real que escrevermos ou quando desenvolvemos para dispositivos embarcados com baixa quantidade de memória. Acessando objetos por referências Quando declaramos uma variável para associar a um objeto, na verdade, essa variável não guarda o objeto, e sim uma maneira de acessá-lo, chamada de referência. É por esse motivo que, diferente dos tipos primitivos como int e long, precisamos dar new depois de declarada a variável, conforme apresenta a Figura 28. O correto aqui é dizer que c1 se refere a um objeto. Não é correto dizer que c1 é um objeto, pois c1 é uma variável referência, apesar de que, depois de um tempo, os programadores Java falarem "Tenho um objeto c do tipo Conta", mas apenas para Figura 28 - Exemplo de referência de objeto utilizando new. Fonte: elaborado pelo autor. encurtar a frase "Tenho uma referência c a um objeto do tipo Conta". Basta lembrar que, em Java, uma variável nunca será um objeto. Não há, no Java, uma maneira de criarmos o que é conhecido como "objeto pilha" ou "objeto local", pois todo objeto em Java, sem exceção, é acessado por uma variável referência, assim como Deitel (2008) trata em seu livro. Mensagens entre objetos AUTORIA Ricardo Bortolo Vieira Agora vamos de�nir outro conceito em OO, assim como menciona Jacobi (2006): mensagens entre objetos. Já aprendemos que um objeto pode possuir diversos métodos de�nidos em sua classe. Em uma aplicação real é muito comum que existam diversos tipos de objetos e que um objeto necessite realizar uma tarefa que já está de�nida em outro objeto, ou seja, numa aplicação poderá haver comunicação e interação entre objetos por meio de mensagens. Em outras palavras, um objeto X pode necessitar de um procedimento (método) já de�nido em um objeto Y. Para realizar esse processo, o objeto X solicita ao objeto Y que execute o método, ou seja, uma mensagem nada mais é do que o fato de um objeto chamar um método de outro objeto (ou ainda um método estático de uma classe). Vamos tentar elucidar com um exemplo. Digamos que um objeto “gerente” precise enviar um e-mail. Ele não sabe como fazer isso, porém o objeto "email" sabe. Então, o objeto "gerente" solicita ao "email" que faça isso por ele. Em orientação a objetos, quando um objeto X solicita a um objeto Y que execute um de seus métodos, diz-se que o objeto X enviou uma mensagem ao objeto Y. Uma mensagem pode conter parâmetros que são valores enviados de um objeto a outro, quando um método for invocado. Observe a Figura 29, em que o objeto "gerente" envia uma mensagem ao objeto "email" (invocandoo método enviar). Serão enviados quatro parâmetros: de, para, assunto e mensagem. Esse padrão do envio de mensagens é de�nido pela UML e pode ser encontrado, por exemplo, em diagramas de comunicação e sequência. REFLITA A maior parte da criatividade é uma transição de um contexto para outro, onde as coisas são mais surpreendentes. Há um elemento de surpresa, e especialmente na ciência, muitas vezes há risos que vão junto com o "Aha". A arte também tem esse elemento. Nosso trabalho é nos lembrarmos de que existem mais contextos do que aquele em que estamos - o que achamos ser realidade. (Alan Kay). ACESSAR https://citacoes.in/citacoes/1923990-alan-kay-our-job-is-to-remind-us-that-there-are-more-contex/ Figura 29 - Mensagem do objeto gerente para o objeto email. 1: enviar(de:String, para:String, assunto:String, mensagem:String) : void gerente : Gerente email : Email Fonte: elaborado pelo autor. O processo de comunicação entre os objetos "gerente" e "email" poderá ser assim descrito: Relação hierárquica entre chamadas de método Como você sabe, e tratado por Jacobi (2006), um método será invocado por uma chamada de método e quando o método chamado terminar sua tarefa, ele retornará o controle e possivelmente um resultado para o chamador. Uma analogia a essa estrutura de programa é a forma hierárquica de gerenciamento, ilustrado na Figura O objeto "gerente" solicita ao objeto "email" o envio de e-mail pelo método "enviar" contido em "email", e fornece os parâmetros adequados; O objeto "email" envia o e-mail usando os dados recebidos de "gerente"; Nesse caso o objeto "email" não fornecerá nenhum retorno para o objeto "gerente" (veja a palavra void adicionada ao �nal da mensagem), mas isso poderia ser diferente e o objeto "email" poderia retornar uma mensagem, por exemplo, informando se houve sucesso ou não no envio. 30 e apresentado a seguir: Um chefe (o chamador) solicita que um trabalhador (o método chamado) realize uma tarefa e informe (retorne) os resultados depois de completar a tarefa. O método chefe não tem conhecimento sobre como o método trabalhador realiza suas tarefas designadas. O trabalhador também poderá chamar outros métodos trabalhadores, sem que o chefe saiba. Essa "ocultação" dos detalhes de implementação promove a boa engenharia de software. A Figura 30 mostra também o método chefe se comunicando com vários métodos trabalhadores de uma maneira hierárquica. O método chefe divide as responsabilidades entre os vários métodos trabalhadores. Aqui, trabalhador1 atuará como um "método chefe" para trabalhador4 e trabalhador5. Figura 30 - Relacionamento hierárquico de método trabalhador / método chefe. Fonte: elaborado pelo autor. Nesta unidade, aprendemos que o Paradigma Orientado a Objeto (OO) nos propicia a elaboração de um código elegante dentro de um projeto de produção de software. Já o projeto é o resultado do re�namento da análise e considerar os detalhes da implementação, tal como a linguagem de programação a ser utilizada, que poderá ser Java, CSharp, C++, Python, ASP.NET, dentro do contexto OO. Juntos pudemos nos familiarizar com o conceito de Orientação a Objetos, que é um paradigma para o desenvolvimento de aplicações, ou seja, é uma estratégia de desenvolvimento de software que organiza o software como uma coleção de objetos, que contém tanto a estrutura dos dados como o comportamento deles. Você pode veri�car que os métodos coesos, dentro de um projeto orientado a objetos, devem fazer apenas uma coisa e fazê-la bem. Isto é, um método não deve executar duas ou mais tarefas, a menos que façam parte de uma mesma ação coesa. Outro princípio relativo a métodos elegantes que você pode veri�car foi que um método não privado deverá manter um objeto em um estado bem formado. Você pode veri�car as características dos principais métodos OO e foi possível veri�car os tipos abstratos de dados, os dois tipos de estruturas que permitem guardar uma coleção de elementos: Estrutura Estática e Estrutura Dinâmica. Você pode veri�car os principais métodos, visualizar as suas características e entrar em contato com os conceitos de OO, em que pode aprender sobre objetos, abstração, classes, operações, atributos, instância, dentre outros. Por �m, você pode veri�car que um objeto pode possuir diversos métodos de�nidos em sua classe. Em uma aplicação real é muito comum que existam diversos tipos de objetos e que um objeto necessite realizar uma tarefa que já está de�nida em outro objeto, ou seja, numa aplicação poderá haver comunicação e interação entre objetos por meio de mensagens. Conclusão - Unidade 1 A partir dos conceitos que foram abordados nesta unidade, você pode ter uma visão geral sobre a Programação Orientada a Objetos. Estaremos juntos na próxima unidade. Até lá! Livro Filme Acesse o link https://www.devmedia.com.br/curso/curso-java-se/423 Unidade 2 Trabalhando com os métodos e suas referências AUTORIA Ricardo Bortolo Vieira Introdução Caro (a) aluno (a), iniciaremos a segunda unidade do livro Programação Orientado a Objetos. Nesta unidade iremos nos aprofundar mais ainda sobre os conceitos OO e v. poderá estudar o uso da palavra reservada this. Poderá também ver como a palavra reservada this será usada para a autorreferência, com atributos e métodos estáticos. Na sequência, será apresentado, os tipos de construtores e sua utilização. Será possível ver que o método construtor será responsável por alocar espaço na memória para a manipulação do objeto e poderá conter também a chamada para outros métodos. Será apresentado o construtor default e as regras para se escrever um método construtor. Em seguida, será apresentada uma visão geral dos operadores e suas estruturas. Você verá que para tratar situações em que o �uxo de execução do programa deverá ser alterado, Java fornecerá um amplo conjunto de estruturas condicionais, de exceção e repetição. Você poderá estudar as estruturas condicionais usados em Programação Orientada a Objetos, que são if-else e switch-case. Essas duas estruturas de desvio existentes na linguagem possibilitam executar diferentes trechos de um programa com base em certas condições. Nesta unidade, também será apresentado os conceitos a respeito das instruções de repetições. Também chamados de looping, formam uma importante estrutura nas linguagens de programação por possibilitarem a repetição da execução de um bloco de instruções em um programa. Tenha um bom aprendizado e um excelente aproveitamento. Então vamos lá! Bons estudos! Uso da palavra reservada this AUTORIA Ricardo Bortolo Vieira Segundo Goodrich (2013), o this é uma palavra reservada que é usada para a autorreferência. Esta situação ocorrerá quando quisermos referenciar a métodos e atributos da própria classe e objeto. Embora seja possível usar o this com atributos e métodos estáticos, será mais usual utilizá-lo com membros de instância. Mais especi�camente ainda, com atributos. O não uso em membros estáticos será simples: estes já pertencem à classe e só existirá uma versão deles. Já com atributos de instância, cada objeto, guardará seu próprio estado neles, e o uso do this poderá ajudar a diferenciar, por exemplos, parâmetros que possam vir a ter o mesmo nome dos atributos. Referenciando Membros do Objeto atual com a Referência this Cada objeto poderá acessar uma referência a si própria, com a palavra chave this (às vezes chamada de referência this). Quando um método de instância for chamado para um objeto particular, o corpo do método utilizará implicitamente a palavra- chave this para referenciar as variáveis de instância do objeto e outros métodos. Isso permite que o código da classe saiba qual objeto deve ser manipulado. Você também poderá usar a palavra chave this explicitamente no corpo do método de uma instância, assim trata Deitel (2017). Agora demonstraremos o uso implícito e explícito da referência this (Figura 31). Esse exemplo é o primeiro em que declaramos duas classes em um único arquivo, a classe ThisTest é declarada naslinhas 2 a 9 e a classe SimpleTime, nas linhas 12 a 45. Isso foi feito para demonstrar que, quando você compilar um arquivo .java que contenha mais de uma classe, o compilador produzirá um arquivo separado da classe com a extensão .class para cada classe compilada. Nesse caso, dois arquivos separados serão produzidos: SimpleTime.class e ThisTest.class. Quando um arquivo de código-fonte (.java) contiver múltiplas declarações de classe, o compilador irá inserir ambos os arquivos de classe para essas classes no mesmo diretório. Observe também na Figura 31, que só a classe ThisTest é declarada public. Um arquivo de código-fonte pode conter somente uma classe public, caso contrário, um erro de compilação ocorrerá. As classes não public só poderão ser utilizadas por outras classes no mesmo pacote. Assim, nesse exemplo, a classe SimpleTime só pode ser usada pela classe ThisTest. A classe SimpleTime (linhas 12 a 45) declara três variáveis de instância private: hour, minute e second (linhas 14 a 16). O construtor da classe (linha 21 a 26) recebe três argumentos int para inicializar um objeto SimpleTime. Mais uma vez, utilizamos nomes de parâmetro para o construtor (linha 21) que são idênticos aos nomes das variáveis de instância da classe (linhas 14 a 18). Assim, usamos a referência this para nos referirmos às variáveis de instância nas linhas 23 a 25. O método buildString (linhas 29 a 34) retorna uma String criada por uma instrução que utiliza a referência this explícita e implicitamente. A linha 34 usa-a explicitamente para chamar o método toUniversalString. A linha 32 utiliza-a implicitamente para chamar o mesmo método. Ambas as linhas realizam a mesma tarefa. Em geral, você não utilizará this explicitamente para referenciar outros métodos dentro do objeto atual. Além disso, a linha 44 no método toUniversalString utiliza explicitamente a referência this para acessar cada variável de instância. Isso não é necessário aqui, porque o método não tem variáveis locais que sombreiam as variáveis de instância da classe. O método main (linhas 4 a 8) da classe ThisTest demonstra a classe SimpleTime. A linha 6 cria uma instância da classe SimpleTime e invoca seu construtor. A linha 7 invoca o método buildString do objeto e então exibe os resultados. Figura 31 - Exemplo de this utilizado implícita e explicitamente como uma referência a membros de um objeto. Fonte: elaborado pelo autor. Construtores AUTORIA Ricardo Bortolo Vieira O operador new é o responsável pelo processo de instanciação do objeto, representando uma forma extremamente simples de atribuir valores default a um objeto. Como o próprio nome diz, o método construtor é o responsável por construir um objeto com determinados valores. O método construtor será responsável por alocar espaço na memória para a manipulação do objeto e poderá conter também a chamada para outros métodos, possibilitando a criação de objetos mais complexos. Na criação de janelas grá�cas (frames), por exemplo, o método construtor pode de�nir todas as propriedades dos componentes visuais do frame (cor do formulário, tamanho dos botões etc.), conforme descreve Furgeri (2015). Construtor default "Se um construtor não for declarado, será assumido um construtor default da linguagem Java, em que as variáveis serão inicializadas com os conteúdos default (variáveis numéricas recebem zero, valores lógicos recebem false e objetos recebem null). Quando declarado, ele deverá possuir, obrigatoriamente, sempre o mesmo nome (idêntico) da classe em que se está localizado. Dependendo das necessidades, uma classe pode conter de zero a N construtores declarados." (Furgeri, 2015 p. 115) Toda a classe Java deverá ter um construtor. Quando não declaramos o construtor, default será inicializado automaticamente pelo Java. Mas existem casos que se faz necessário à declaração explícita dos construtores. O Construtor não poderá ser herdado. Para chamá-lo a partir de uma subclasse usamos a referência super. Para escrever um construtor, devemos seguir algumas regras: O nome do construtor precisa ser igual ao nome da classe; Não deve ter tipo de retorno; Esta sintaxe pode ser vista na Figura 32 e um exemplo dessa declaração na Figura 33. Chamando Outro Construtor Um construtor só poderá ser executado durante a construção do objeto, depois disso, você não conseguirá chamar o construtor em um objeto já tenha sido construído. Porém, para você não ter que �car copiando e colando, você poderá fazer um construtor chamar outro construtor, durante a construção de um objeto. Essa técnica é apresentada por Silveira (2006) e poderá ser vista na Figura 34. Podemos escrever vários construtores para mesma classe. Figura 32 - Representação da sintaxe de um construtor. Fonte: elaborado pelo autor. Figura 33 - Exemplo de sintaxe de um construtor na classe Mamifero. Fonte: elaborado pelo autor. Ainda seguindo a técnica de Silveira (2006), existe outro motivo para a utilização desta técnica, a facilidade para sua implementação. Poderemos criar um construtor que receberá diversos argumentos para que o usuário de uma classe não seja obrigado a chamar diversos métodos do tipo set(). Figura 34 - Exemplo de chamada de outro construtor. Fonte: elaborado pelo autor. SAIBA MAIS Quando implementamos uma classe com todos os seus atributos privados, seus métodos getters() e setters() e um construtor default (vazio), na verdade nós estaremos criando um Java Bean, que não deverá ser confundido com o EJB, que é Enterprise Java Beans. Para saber mais acesse: ACESSAR http://java.sun.com/products/javabeans/ Visão geral dos operadores AUTORIA Ricardo Bortolo Vieira Dentro de um método, a execução prosseguirá na sequência em que as instruções ocorrerem. Em outras palavras, a execução se dará, a partir do cabeçalho do método para a próxima, de cima para baixo. No entanto, as regras de negócios nos exibem alterar esse �uxo para contemplar condições diferentes. Essas situações são extremamente comuns em programação. Por exemplo: um site poderá pedir uma senha e seu código não deverá dar acesso a ele, se a senha for inválida. Logo, o código que dará acesso não deverá ser executado, se uma senha inválida for inserida. Se uma senha inválida for inserida, você poderá dar ao usuário mais duas (e somente duas) oportunidades de inseri-la corretamente. Para tratar situações em que o �uxo de execução do programa deverá ser alterado, Java fornecerá um amplo conjunto de estruturas condicionais, de exceção e repetição. Estruturas Condicionais Schildt (2013) trata sobre as estruturas condicionais existem em todas as linguagens de programação e descreve como elas possibilitam que a execução de um programa, seja desviada de acordo com certas condições. Os comandos condicionais ou ainda instruções condicionais, usados em Java, são if-else e switch- case. Essas duas estruturas de desvio existentes na linguagem possibilitam executar diferentes trechos de um programa com base em certas condições. A Estrutura if-else Schildt (2013) ainda trata sobre o if, em conjunto com o else, formando uma estrutura que permite a seleção entre dois caminhos distintos para execução, dependendo do resultado (verdadeiro ou falso) de uma expressão lógica (condição). Nesse tipo de estrutura, se a condição for verdadeira, serão executadas as instruções que estiverem posicionadas entre as instruções if/else. Sendo a condição falsa, serão executadas as instruções que estiverem após a instrução else. A sintaxe para a utilização do conjunto if else será demonstrada em seguida. Observe, na Figura 35, que a condição sempre deverá aparecer entre parênteses, item obrigatório na linguagem Java. SAIBA MAIS Os 4 pilares da Programação Orientada a Objetos Caro (a) aluno (a), com a �nalidade de ampliar o conhecimento voltado à programação orientada a objetos, ofereço a você como sugestão para leitura este artigo que trata dos quatro pilares da programação orientada a objetos, que são a abstração, encapsulamento, herança e o polimor�smo. Estassão as bases da programação orientada a objetos, quando se tem a perfeita compreensão sobre elas, você poderá ter um desenvolvimento de software melhor e com maior facilidade na hora de programar. "O desenvolvimento de software é extremamente amplo. Nesse mercado, existem diversas linguagens de programação, que seguem diferentes paradigmas. Um desses paradigmas é a Orientação a Objetos, que atualmente é o mais difundido entre todos. Isso acontece porque se trata de um padrão que tem evoluído muito, principalmente em questões voltadas para segurança e reaproveitamento de código, o que é muito importante no desenvolvimento de qualquer aplicação moderna"... ACESSAR https://www.devmedia.com.br/os-4-pilares-da-programacao-orientada-a-objetos/9264 A Figura 36 traz uma representação grá�ca para ajudá-lo a entender o funcionamento dessa estrutura. Cada losango poderá ser considerado uma instrução if que contém uma expressão lógica (condição). Veja que dependendo do resultado da condição (verdadeira ou falsa) será executado um bloco diferente (1 ou 2) de instruções. É importante entender também que toda estrutura if possui um início e um �nal, nos quais os dois caminhos se encerram. Figura 36 - Representação grá�ca da instrução if else. Início Condição [verdadeira] [falsa] bloco 1 bloco 2 Fim Fonte: FURGERI, 2015, p.43 Figura 35 - Exemplo de sintaxe para a utilização do conjunto if else. Fonte: elaborado pelo autor. “Assim como a maioria das instruções em Java, o conjunto if-else deverá ser utilizado com minúsculas e, caso haja apenas uma instrução a ser executada, tanto no if como no else, o uso das chaves será desnecessário. Lembre-se de que as chaves serão utilizadas quando um bloco de instruções precisa ser executado, isto é, mais do que uma instrução. A estrutura if-else apresentada não é a única válida, pois existem outras maneiras diferentes de se criar essa estrutura: if sem o else, if com o else e if com o else aninhado.” (FURGERI, 2015, p.43). Compare as representações grá�cas dessas variações nas Figuras 37, 38 e 39. Figura 37 - Representação grá�ca da instrução if sem else. Fonte: (FURGERI, 2015, p.43). Figura 38 - Representação grá�ca da instrução if com else. Início Condição [verdadeira] [falsa] bloco 1 bloco 2 Fim Fonte: (FURGERI,2015, p.44). Figura 39 - Representação grá�ca da instrução if com else aninhado. Condição [verdadeira] [falsa] Condição [verdadeira] [falsa] Início Condição [verdadeira] [falsa] bloco 1 bloco 2 bloco 3 bloco 4 Fim Fonte: (FURGERI, 2015, 44). No primeiro caso é executado um bloco de instruções somente se a condição for verdadeira; no segundo caso será executado um bloco de instruções para a condição verdadeira e outro para a falsa. Já no terceiro caso, quando encontrada a primeira condição verdadeira todas as outras serão desconsideradas. Seja o caminho que for apenas um bloco de instruções será executado. O terceiro caso demonstra que para cada condição falsa, será executada outra condição, mas poderia ser representado ao contrário, ou seja, a condição verdadeira poderia levar à execução de outra condição. Estrutura 1: if sem else O Exemplo apresentado na Figura 40, mostra um uso prático do if sem a presença do else. Trata-se de uma classe em que o usuário seleciona uma opção (Masculino ou Feminino) e a partir disso será usada a instrução if para executar instruções diferentes. Figura 40 - Exemplo da listagem da classe if. Fonte: elaborado pelo autor. O Exemplo da Figura 42, mostra um uso prático do if-else para validar a entrada do usuário. Serão realizadas três validações: em primeiro lugar, veri�ca se o usuário realmente entrou com um valor na caixa de diálogo, depois veri�ca se o valor digitado é numérico, logo a seguir veri�ca se esse valor está entre 1 e 12 (a faixa de valores possíveis, uma vez que um mês deverá assumir apenas valores entre 1 e 12). Figura 41 - Tela de execução da Figura 40 com seleção de Feminino. Fonte: (FURGERI, 2015, 46). Figura 42 - Listagem da classe IfComElse. Fonte: elaborado pelo autor. O Exemplo 44, mostra como é possível criar uma estrutura em que cada instrução else realiza a abertura de um novo if. Ao analisar essa estrutura, podemos notar que existe um (ou mais) if dentro de um else. Estrutura switch-case “A estrutura switch-case se refere à outra modalidade de desvio da execução do programa de acordo com certas condições, semelhante ao uso da instrução if. Ao trabalhar com uma grande quantidade de desvios condicionais contendo instruções Figura 43 - Tela de execução da Figura 42 com seleção do mês 5. Fonte: (FURGERI, 2015, 47). Figura 44 - Listagem da classe IfComElseAninhado Fonte: elaborado pelo autor. if, pode-se comprometer a inteligibilidade do programa, di�cultando sua interpretação. A estrutura switch-case possibilita uma forma mais adequada e e�ciente de atender a esse tipo de situação, constituindo-se uma estrutura de controle com múltipla escolha.” (FURGERI, 2015, 48). A estrutura switch-case equivale a um conjunto de instruções if encadeadas, fornecendo maior inteligibilidade. Sua sintaxe é a apresentada na Figura 45. Na primeira linha do switch é avaliado o resultado da expressão, que é comparado nas diretivas case, executando o bloco de instruções quando a expressão coincidir com o valor colocado ao lado direito do case. Em outras palavras, supondo que o valor da expressão seja igual a 2, serão executadas as instruções localizadas entre case 2: e break. A cada case o programa compara o valor da expressão com o valor colocado no case. Caso os valores sejam iguais, todas as instruções serão executadas até que se encontre uma instrução break, que encerra o switch e faz a execução do programa desviar para o ponto após a chave de encerramento do switch. O programa percorre todas as diretivas case até que uma delas seja igual à expressão inserida no switch. Caso nenhuma diretiva case possua o valor correspondente da expressão, serão executadas as instruções localizadas na diretiva default que será opcional. Veja a representação grá�ca da estrutura do switch-case na Figura 46. Figura 45 - Exemplo de sintaxe da estrutura switch-case. Fonte: elaborado pelo autor. Figura 46 - Representação grá�ca da estrutura switch-case. Condição Condição Início Condição [verdadeira] [verdadeira] [verdadeira] [falsa] [falsa] [falsa] Instruções Instruções Instruções Fim Expressão Fonte: (FURGERI, 2015, p.49). O Exemplo da Figura 47, demonstra de forma clara a utilização da estrutura switch- case, simulando os meses do ano, em que o usuário entra com um número e o programa retorna o mês correspondente por extenso. Figura 47 - Listagem da classe SwitchCase. Fonte: elaborado pelo autor. Figura 48 - Tela de execução da Figura 47 com seleção do mês 2. Fonte: (FURGERI, 2015, p.50). Instruções de repetições AUTORIA Ricardo Bortolo Vieira "Os laços de repetição (looping) formam uma importante estrutura nas linguagens de programação por possibilitarem a repetição da execução de um bloco de instruções em um programa. Eles determinam que um certo bloco seja executado repetidamente até que uma condição especí�ca ocorra. A repetição é uma das estruturas mais usadas em programação, possibilitando a criação de contadores, temporizado- res, rotinas para classi�cação, obtenção e recuperação de dados. A criação de laços de repetição em Java é feita a partir das estruturas for, while e do-while" (FURGERI, 2015, p.56). Instrução de Repetição While Tucker (2009) trata uma instrução de repetição como uma especi�cação que um programa deverá repetir uma ação enquanto alguma condição permanecer verdadeira. A instrução de pseudocódigo descreve a repetição durante uma viagem de compras. A condição "enquanto houver mais itens em minha lista de compras" poderá ser verdadeira ou falsa. Se ela for verdadeira, então a ação "Compre o próximo item e risque-o de minha lista" será realizada. Essa ação será realizada repetidamente, enquanto a condição permanecer verdadeira.A(s) instrução (ões) contida(s) na trecho de código de repetição While constitui (em) seu corpo, que poderá ser uma instrução única ou um bloco. Por �m, a condição se tornará falsa, quando o último item da lista de compras tiver sido comprado e removido. Neste ponto, a repetição termina e a primeira instrução depois da instrução de repetição será executada, conforme trata Deitel (2013). Condição: poderá ser qualquer expressão ou valor que resulte em um verdadeiro ou falso. O laço while será executado enquanto a condição for verdadeira. Quando esta se tornar falsa o programa continua no próximo comando após o while. Figura 49 - Sintaxe da instrução de repetição While. Fonte: elaborado pelo autor. Para instrução de repetição while, o teste da condição de controle será feito no início do laço, o que signi�ca que se já for falsa os comandos dentro do laço não serão executados. Tucker (2009) ainda detalha a instrução while, apresentada na Figura 49, avaliando o resultado da expressão (condição) antes de executar as instruções do bloco { }. Assim, será possível que as instruções nunca sejam executadas, caso a condição seja inicialmente falsa. Um problema típico, relacionado à avaliação da condição while, é o laço in�nito. Caso a condição nunca se torne falsa, o laço será repetido in�nitamente. Um exemplo do laço While está presente na Figura 50. Figura 50 - Exemplo da instrução de repetição while na classe WhileDemo. Fonte: elaborado pelo autor. Há outro tipo de laço condicional, o chamado do-while, que é bem parecido com o while, porém o conjunto de instruções será executado antes da avaliação da expressão lógica. Isso faz com que essas instruções sejam executadas pelo menos uma vez, conforme apresenta Furgeri (2015). Veja como a sintaxe do do-while é bem parecida com a do while na Figura 51. REFLITA "Algumas pessoas acham que foco signi�ca dizer sim para a coisa em que você vai se focar. Mas não é nada disso. Signi�ca dizer não às centenas de outras boas ideias que existem. Você precisa selecionar cuidadosamente." (Steve Jobs). Inspirado em uma das maiores mentes da computação, Steve Jobs, hoje é o dia certo para estudar, trabalhar, buscar algo novo. Mas, não devemos fazer isso tentando abraçar o mundo, ou seja, tentando fazer tudo ao mesmo tempo, mas sim, um de cada vez, porém de forma completa e totalmente envolvida. Assim, priorizar será a competência que você deverá aprimorar, somente assim será capaz de ir além e fazer coisas que outros não podem. Hoje é o dia! Faça o hoje valer a pena, fazendo boas escolhas! ACESSAR Figura 51 - Sintaxe da instrução de repetição do-while. Fonte: elaborado pelo autor. https://www.tecmundo.com.br/internet/3145-frases-impactantes-sobre-tecnologia-e-informatica.htm Embora as chaves não sejam necessárias quando houver apenas uma instrução presente, elas serão usadas com frequência para melhorar a legibilidade da estrutura do-while, evitando, assim, confusão com while. O laço do-while será executado enquanto a expressão condicional for verdadeira. O programa apresentado na Figura 52 demonstra o uso do do-while �cando em laço até você adivinhar a letra. Instrução de Repetição For Ainda temos Knudsen (2005) tratando sobre a instrução for como um tipo de contador �nito, isto é, ela realiza a contagem de um valor inicial conhecido até um valor �nal também conhecido. Uma possível representação grá�ca da estrutura de funcionamento de um laço de repetição for poderá ser visualizada na Figura 53. No início da execução da estrutura será inicializada uma variável. Após isto, o valor dessa variável será veri�cado na condição, na representação grá�ca do losango, e enquanto essa condição for verdadeira o bloco de instruções será executado dentro da estrutura. Somente quando a condição se tornar falsa é que a execução será desviada para o �nal da estrutura do laço. O incremento ou decremento do valor da variável será essencial para que o laço tenha uma saída (encerre), caso contrário, a execução nunca sairá do laço. Figura 52 - Exemplo da instrução de repetição do-while, na classe Adivinhar4. Fonte: elaborado pelo autor. A Figura 54 examina mais detalhadamente a instrução for. O cabeçalho de for é o "faz tudo", ele especi�cará cada item necessário para repetição controlada por contador, com uma variável de controle. Se houver mais de uma instrução no corpo do for, as chaves ({ e }) serão exigidas para de�nir o corpo do loop. Figura 53 - Representação grá�ca da instrução for. Início [verdadeira] Condição [falsa] Instruções Incremento/decremento Inicialização da variável Fim Fonte: (FURGERI, 2015, p.57). Figura 54 - Componentes de cabeçalho de instrução for. Fonte: (DEITEL, 2017, p.122). O formato geral da instrução for é apresentada na Figura 55. Segundo Deitel (2017, p. 123): “a expressão inicialização nomeará a variável de controle do loop e opcionalmente fornecerá seu valor inicial, condiçãoDeContinuaçãoDoLoop será a condição que determinará se o loop deverá continuar executando e o incremento modi�cará o valor da variável de controle, para que a condição de continuação do loop, por �m se torne falsa. Os dois pontos e vírgulas no cabeçalho for serão necessários. Se a condição de continuação do loop for inicialmente false, o programa não executará o corpo da instrução for. Em vez disso, a execução prosseguirá com a instrução seguinte ao for.” A instrução for muitas vezes poderá ser representada com uma while equivalente da maneira descrita na Figura 56. Figura 55 - Sintaxe da instrução de repetição for. Fonte: elaborado pelo autor. Funcionalidades comentadas no exemplo da Figura 57: Linhas 5 a 7: contém os laços de repetição para o controle das horas (0 a 23), minutos (0 a 59) e segundos (0 a 59). Um ponto a ser observado será a possibilidade de criação de um laço de repetição dentro do outro. Quando isso ocorre, o laço interno é executado n vezes, de acordo com o número de vezes de�nido pelo laço superior. Como exemplo, observe as linhas 7 a 18. O laço mais interno (s) controla os segundos e é executado 60 vezes a cada minuto (o laço superior). Da mesma forma, o laço dos minutos será executado 60 vezes a cada hora (o laço superior). Figura 56 - Sintaxe da instrução de repetição for representada por while. Fonte: elaborado pelo autor. Figura 57 - Exemplo da instrução de repetição for na simulação de um relógio. Fonte: elaborado pelo autor. Linha 10: contém sleep (1000); que invoca um temporizador que espera mil milissegundos (um segundo) até a execução da próxima instrução. Esse procedimento poderá gerar uma exceção e por isso deverá ser usado dentro de um bloco try, ou poderá ser desconsiderado caso você pre�ra usar a cláusula throws. No último caso, o exemplo �caria um pouco mais resumido: deveria ser adicionado "throws InterruptedException" ao �nal da linha 3 e retiradas as linhas 9 e 13 a 16. O uso de Thread talvez não seja a melhor forma de se criar uma temporização; para isso existem outras classes como Timer e TimerTask, cujo estudo foge aos objetivos. Também não é objetivo estudar threads. Além disso, o uso do método sleep dentro de um laço de repetição não é muito recomendado por questões de desempenho. Linhas 11 e 12: controlam o �nal da execução do relógio. Quando o relógio contar dez segundos, o programa será encerrado por meio de exit (0). Sempre que for necessário forçar o encerramento de um programa, o método exit poderá ser usado. Se você estiver usando uma IDE (NetBeans, Eclipse) existe um botão especí�co para isso, um botão de stop, normalmente um quadradinho vermelho. Os resultados obtidos ao executar o exemplo da Figura 57 poderão ser vistos na Figura 58. Figura 58 - Saída do código apresentado no exemplo da Figura 57. Fonte: elaborado pelo autor. Caro(a) aluno(a) que bom que chegou até aqui! Nosso objetivo foi apresentar-lhes os conceitos e exemplos para facilitar o entendimento de uma das linguagens mais usadas na programação na atualidade, a Programação Orientada a Objetos. Com uma
Compartilhar