



























Estude fácil! Tem muito documento disponível na Docsity
Ganhe pontos ajudando outros esrudantes ou compre um plano Premium
Prepare-se para as provas
Estude fácil! Tem muito documento disponível na Docsity
Prepare-se para as provas com trabalhos de outros alunos como você, aqui na Docsity
Encontra documentos específicos para os exames da tua universidade
Prepare-se com as videoaulas e exercícios resolvidos criados a partir da grade da sua Universidade
Responda perguntas de provas passadas e avalie sua preparação.
Ganhe pontos para baixar
Ganhe pontos ajudando outros esrudantes ou compre um plano Premium
- - -
Tipologia: Notas de estudo
1 / 35
Esta página não é visível na pré-visualização
Não perca as partes importantes!




























Fábio Mengue – [email protected] Centro de Computação - Unicamp
Em 1991, um grupo de engenheiros da Sun Microsystems foi encarregado de criar uma nova linguagem que pudesse ser utilizada em pequenos equipamentos como controles de TV, telefones, fornos, geladeiras, etc. Essa linguagem deveria dar a esses aparelhos a capacidade de se comunicar entre si, para que a casa se comportasse como uma federação. Deveria ainda ser capaz de gerar códigos muito pequenos, que pudessem ser executados em vários aparelhos diferentes, e praticamente infalível.
Os engenheiros escolheram o C++ como ponto de partida. Orientada a objetos, muito poderosa e gerando pequenos programas, parecia a escolha correta. Para solucionar o problema da execução em várias arquiteturas, eles utilizaram o conceito da máquina virtual, onde cada fabricante iria suportar algumas funções básicas que os programas utilizariam.
Até hoje a linguagem resultante deste projeto não é utilizada em aparelhos eletrodomésticos. Ao invés disso, o Java se tornou um das linguagens de programação mais utilizadas no planeta.
Na maioria das linguagens de programação, você precisa compilar ou interpretar um programa para que ele seja executado em seu computador. A linguagem Java é diferente, pois seus programas são compilados E interpretados. Com o compilador, você inicialmente transforma seu programa em uma linguagem intermediária, chamada bytecode. Esse código é independente de plataforma, e é mais tarde interpretado por um interpretador Java. A compilação acontece apenas uma vez; a interpretação acontece todas as vezes que seu programa é executado. A figura abaixo mostra como isso acontece.
Você deve pensar nos bytecodes como instruções de máquina para a Java Virtual Machine (ou JVM). Todos os produtos que conseguem executar programas em Java (como um browser que executa applet’s) possuem uma cópia da JVM.
Bytecodes Java tornam possível a tecnologia “escreva uma vez, execute em qualquer lugar”. Você pode compilar seu programa Java em qualquer plataforma que possua um compilador. Os bytecodes gerados podem ser interpretados em qualquer plataforma que possua uma JVM. Veja na figura abaixo:
A Plataforma Java
Por plataforma, entendemos o conjunto de hardware e software no qual um programa executa. Alguns exemplos de plataformas muito usadas são o Windows, o Linux, o MacOS. A plataforma Java é diferente, pois não envolve hardware; ela utiliza a plataforma de hardware das outras.
A plataforma Java tem dois componentes:
A API Java é uma coleção de componentes de software prontos, que incluem desde estruturas para manipulação de arquivos até a construção de aplicativos gráficos. A API é organizada como um grupo de bibliotecas com classes e interfaces; essas bibliotecas são chamadas de pacotes.
A figura abaixo mostra o esquema de funcionamento da plataforma Java:
Para o desenvolvimento de aplicativos utilizando o Java, é necessário a instalação do compilador Java, das API’s e da JVM. A instalação do ambiente segue o mesmo esquema da instalação de qualquer produto para Windows.
Devemos fazer o download da versão mais apropriada via ftp ou http e executar o arquivo, para que o produto se instale.
As versões para Windows, Linux e Solaris pode ser obtido em:
http://java.sun.com
Como a maioria das linguagens de programação, o fonte de seu programa em Java deve ser criado a partir de um editor de texto que gere arquivos em formato ASCII. É possível utilizar editores como o Word e o Wordpad, mas o texto deve ser salvo sem formatação. O editor ideal é o notepad.
O programa fonte em Java deve ser salvo obrigatoriamente com a extensão .java. Salve no notepad o arquivo utilizando aspas duplas, assim:
“AloMundo.java”
Vamos então criar uma pasta chamada CURSO (md curso) para que possamos organizar os programas e exercícios que faremos.
Execute o Notepad agora, e vamos digitar nosso primeiro programa em Java. Copie as linhas abaixo:
class AloMundo {
public static void main(String args[]) {
System.out.println(“Alo Mundo !”);
} }
Não se preocupe em entender o código; é apenas um exemplo, e explicaremos esses comandos mais tarde. Salve o arquivo como AloMundo.java (letras maiúsculas e minúsculas são importantes).
A seguir, vamos compilar o programa. A compilação irá gerar os bytecodes. Do prompt do DOS, execute:
javac AloMundo.java
Se não houver erro, depois de alguns segundos você deve ter acesso ao prompt novamente. Para executar o programa,
java AloMundo
Você deve ter recebido como resposta a frase “Alo Mundo !”. Isso significa que tudo está certo com seu ambiente e você acabou de criar seu primeiro programa em Java.
Exercícios
–Altere o programa AloMundo para que ele imprima seu nome completo. –Altere o programa AloMundo e faça com que ele imprima seu nome em duas linhas separadas.
Temos aqui representada (de maneira lógica) a idéia que as linguagens orientadas a objeto utilizam. Tudo que um objeto sabe (estados ou variáveis) e tudo que ele podem fazer (comportamento ou métodos) está contido no próprio objeto.
No exemplo da bicicleta, poderemos representar o objeto como no exemplo abaixo:
Temos métodos para mudar a marcha, a cadência das pedaladas, e para brecar. A utilização desses métodos altera os valores dos estados. Ao brecar, a velocidade diminui. Ao mudar a marcha, a cadência é alterada.
Note que os diagramas mostram que as variáveis do objeto estão no centro do mesmo. Os métodos cercam esses valores e os “escondem” de outros objetos. Deste modo, só é possível ter acesso a essas variáveis através dos métodos. Esse tipo de construção é chamada de encapsulamento, e é a construção ideal para objetos.
Exercício
Mas um objeto sozinho geralmente não é muito útil. Ao contrário, em um programa orientado a objetos temos muitos objetos se relacionando entre si. Uma bicicleta encostada na garagem nada mais é que um pedaço de ferro e borracha. Por si mesma, ela não tem capacidade de realizar nenhuma tarefa. Apenas com outro objeto (você) utilizando a bicicleta, ela é capaz de realizar algum trabalho.
A interação entre objetos é feita através de mensagens. Um objeto “chama” os métodos de outro, passando parâmetros quando necessário. Quando você passa a mensagem “mude de marcha” para o objeto bicicleta você precisa dizer qual marcha você deseja.
A figura a seguir mostra os três componentes que fazem parte de uma mensagem:
A troca de mensagens nos fornece ainda um benefício importante. Como todas as interações são feitas através delas, não importa se o objeto faz parte do mesmo programa; ele pode estar até em outro computador. Existem maneiras de enviar essas mensagens através da rede, permitindo a comunicação remota entre objetos.
Assim, um programa orientado a objetos nada mais é do que um punhado de objetos dizendo um ao outro o que fazer. Quando você quer que um objeto faca alguma coisa, você envia a ele uma "mensagem" informando o que quer fazer, e o objeto faz. Se ele precisar de outro objeto que o auxiliar a realizar o "trabalho", ele mesmo vai cuidar de enviar mensagem para esse outro objeto. Deste modo, um programa pode realizar atividades muito complexas baseado apenas em uma mensagem inicial.
Você pode definir vários tipos de objetos diferentes para seu programa. Cada objeto terá suas próprias características, e saberá como interpretar certos pedidos. A parte interessante é que objetos de mesmo tipo se comportam de maneira semelhante. Assim, você pode ter funções genéricas que funcionam para vários tipos diferentes, economizando código.
Vale lembrar que métodos são diferentes de procedimentos e funções das linguagens procedurais, e é muito fácil confundir os conceitos. Para evitar a confusão, temos que entender o que são classes.
Exercícios
Até agora, comentamos sobre o que é um objeto e como ele se relaciona com outros objetos. Falaremos agora a respeito de classes.
Sua bicicleta é apenas uma das várias que existem. A sua bicicleta específica foi feita por um fabricante, e tem certas características que seguem uma linha ou modelo. Assim, é possível ir em uma loja e comprar várias unidades de bicicletas essencialmente idênticas. Mas não podemos dizer que todas são o mesmo objeto, simplesmente por serem parecidas.
Em orientação a objetos, dizemos que um (ou mais) objetos pertencem a uma classe quando eles são muito semelhantes, de acordo com certos padrões. Assim, dependendo da situação, alguém pode dizer que sua bicicleta é um veículo, pois ele anda sobre rodas e carrega uma pessoa. Se seguirmos esse padrão, uma motocicleta também é um veículo, assim como um automóvel ou até um avião (ué, não anda sobre rodas quando decola ou pousa? Não carrega uma pessoa ?). Na verdade, quando programamos em linguagens orientadas a objetos, antes de tudo nós construimos as classes, os modelos, para depois usá-las na criação de objetos daquele tipo.
Voltando ao exemplo da lâmpada, em Java eu poderia definir uma lâmpada assim:
lampada sala_de_aula = new lampada();
Se eu quiser ligar a lâmpada, é só informar a ela o meu desejo, através de uma mensagem:
sala_de_aula.ligar();
E a lâmpada vai acender. Não me importa como ela fez isso, me importa apenas que ela faça.
Não basta um objeto estar definido para ser utilizado. Se eu pretendo usar um objeto, eu preciso cria-lo, e atribuir o controle desse objeto a um nome. A criação de objetos em Java é sempre necessária, e é chamada de instanciação (por isso o objeto é chamado de instância).
Quando eu crio o objeto sala_de_aula, eu digo que ele é do tipo lâmpada e que eu quero que ele seja instanciado nesse momento (new lampada()). A partir de agora, sala_de_aula é um objeto do tipo definido e tem como funções tudo que uma lâmpada pode fazer.
Uma das grandes vantagens do Java e nosso propósito de estudo é a capacidade de você definir seus próprios objetos. Como já comentado, um objeto contém atributos (dados) e métodos (funções para manipulação dos dados). Esses objetos irão ajudá-lo a resolver o problema apresentado e tornarão seu trabalho mais fácil.
Vamos inicialmente criar um objeto simples, que contenha apenas dados.
class meuObjeto { String nome; int idade; String telefone; }
Você acabou de definir um objeto chamado meuObjeto. Temos nome, idade e telefone como dados deste objeto.
Mas não basta defini-lo para que ele nos seja útil. Para isso, você deve instanciá-lo,
assim:
meuObjeto amigo = new meuObjeto();
A partir de agora, meu objeto amigo pode ser utilizado para guardar dados. Eu posso incluir dados assim:
amigo.nome = "Joao"; amigo.idade = 33; amigo.telefone = "2223311";
E quando eu precisar dos valores, eu simplesmente os imprimo.
Nota: para facilitar nosso aprendizado, o comando para imprimir um dado é System.out.println, e pode ser utilizado assim:
System.out.println (amigo.nome);
Vamos agora criar um método para o meuObjeto. Esse método vai se chamar aniversario, e ele serve para aumentar em 1 ano a idade do objeto. Então, meu objeto ficaria:
class meuObjeto { String nome; int idade; String telefone;
public void aniversario() { idade = idade + 1; } }
Agora, para um teste, poderíamos fazer:
meuObjeto amigo = new meuObjeto(); amigo.nome = "Joao"; amigo.idade = 33; amigo.telefone = "2223311"; System.out.println ("Idade antiga"+amigo.idade); amigo.aniversario(); System.out.println ("Nova idade"+amigo.idade);
Percebam que o valor da idade foi alterado.
idade = nova_idade; } E a chamada ao método ficaria:
amigo.alteraIdade(30);
Exercício
Nota: Caso eu tenha mais de um argumento, eles devem ser separados por virgulas. Nota2: Na definição do método com mais de um argumento, eu tenho que prever as variáveis a serem recebidas.
Exemplo: void qualquerCoisa (String nome, int idade, String telefone)
A chamada é
amigo.qualquerCoisa ("paulo", 24, "2221133");
Vocês podem estar se perguntando qual a finalidade de criar métodos para alterar valores dentro de um objeto. Nesses exemplos fica fácil perceber que é muito mais fácil fazer uma atribuição simples (amigo.idade=34) do que criar um método só para alterar a idade. Mas isso tem sentido de ser, em linguagens orientadas a objetos.
A idéia é que o objeto deve gerenciar seus próprios dados, que só devem ser acessíveis ao "mundo exterior" através de seus métodos (excetuando-se aqui os métodos e variáveis estáticas). Então, pelo menos em teoria, cada atributo do meu objeto deve ter um método para gravar dados e outro para devolver o dado gravado. Isso vai permitir que esse objeto seja utilizado por qualquer um, a qualquer tempo.
Vamos passar então um pequeno código de um programa completo em Java para que possamos ir comentando e esclarecendo.
import java.util.*; public class Propriedades { public static void main (String[] args) { System.out.println ("Bom dia... Hoje é dia\n"); System.out.println(new Date()); }}
Logo na primeira linha temos "import...". É normal nas primeiras linhas de um programa em Java a colocação da instrução import. Essa instrução serve para que nosso programa possa utilizar qualquer classe externa que ele necessite. No caso, meu programa usa uma função que retorna a data do sistema, e essa função faz parte de java.util. Assim, eu preciso importar essas funções para que meu programa funcione. Isso será explicado melhor quando falarmos a respeito de API's.
Na segunda linha, definimos o nome desse objeto (em Java, chamado de classe). É importante notar que o objeto deve ter o mesmo nome do arquivo no disco, caso contrário o programa não irá funcionar.
Notamos ainda nessa mesma linha que essa classe é do tipo publica (public). Isso quer dizer que esse objeto é acessível por outros objetos, que ele pode ser importado e usado.
Na próxima linha, temos a definição do método main. Vemos novamente o public, e a palavra static, indicando que esse método não pode ser instanciado, apenas usado do jeito que esta. Vemos que o método main admite uma lista de Strings como argumentos (chamado de args). Esses argumentos não são necessários nesse programa, mas caso necessitássemos de passar algum tipo de informação para o programa, essas informações estariam armazenadas na variável args.
Na próxima linha, temos a impressão de um texto na tela. A única novidade é a presença de um sinal \n no final do texto. Ele indica ao Java para pular de linha depois de escrever o texto indicado.
Na ultima linha temos outra impressão. Dessa vez, temos a instanciação de um objeto do tipo Date, e seu valor é imediatamente impresso. Como não necessitamos do objeto, apenas queremos um valor impresso, não é necessário criar uma variável apenas para isso. Note que nem sempre isso é possível.
Como já apresentado, é sempre necessário instanciar um objeto para poder utilizá-lo. Existe um método especial em uma classe que fornece instruções a respeito de como devemos instanciar o objeto. Esse método é chamado de construtor.
A função do construtor é garantir que o objeto associado à variável definida será inciada corretamente. Sempre é necessário ter um construtor, e como na maioria das vezes esse construtor não faz nada (além de instanciar o objeto), não é necessário declara-lo. O Java faz isso automaticamente para nos.
Nota: O método construtor tem exatamente o mesmo nome da classe. Assim, no exemplo:
Agora meuObjeto pode ser instanciado como
meuObjeto amigo = new meuObjeto();
ou
meuObjeto amigo = new meuObjeto("Joao", 32, "2223311");
A sobrecarga é um dos recursos mais interessantes da orientação a objetos. E não esta restrito aos construtores; podermos definir o mesmo nome de método para qualquer método. Assim, tornamos o programa mais legível e temos menos nomes para "inventar".
Nota: Como os dois (ou mais) métodos tem o mesmo nome, a diferenciação de qual método é executado depende da quantidade e do tipo dos argumentos enviados.
Nota2: Quando não definimos construtores, o Java cria um sem argumentos para nos. Quando eu escolho definir o construtor, tenho que definir para todos os tipos, inclusive o sem argumentos.
Como já falado, existem muitos objetos prontos que a linguagem Java nos proporciona. Como todos os objetos, eles podem conter dados e tem vários métodos para que possamos usa- los. É importante para um programador Java conhecer o máximo desses objetos que puder; eles facilitam o trabalho na medida que evitam que nos tenhamos o trabalho de inventar algo que já está pronto. Lembre que normalmente nós não temos acesso aos atributos dessa classe; apenas a seus métodos.
Quando executamos um import ... no inicio do nosso programa, estamos informando ao compilador Java quais as classes que desejamos usar.
Assim, um import java.util.*; quer dizer: "eu vou utilizar alguns objetos do pacote java.util". Um programa pode ter tantos import quanto necessário.
Isso permite que você utilize componentes de pacotes baixados da Internet, com utilização mais restrita.
Nota: Uma lista completa das API's existentes pode ser achada na lista de links no final do documento.
Um pacote pode ser entendido como uma serie de objetos agrupados por afinidade. Eles ficam "juntos" pois tem funções semelhantes (como por exemplo manipular texto).
Quando nós vamos criar nossos próprios objetos para resolver um problema, normalmente esses objetos ficam todos no mesmo sub-diretorio; entre eles estabelecemos uma relação de "amizade", e podemos considera-los como parte do mesmo pacote (default). Estando no mesmo sub-diretorio, certas restrições de acesso entre esses objetos mudam. Explicamos restrição de acesso no tópico a seguir.
As restrições de acesso em Java existem por dois motivos. O primeiro é não permitir que o programador utilize meus objetos da maneira que quiser. Eu dito o que pode e o que não pode ser utilizado. E o segundo motivo é que tudo que não for publico (e consequentemente não permite acesso) pode ser alterado na hora que eu quiser. Contanto que os métodos de acesso (que são públicos) fiquem inalterados, ninguém vai perceber a diferença.
Como exemplo, vejamos o objeto String. O String na verdade é um vetor de caracteres. Eu não tenho permissão para acessar os conteúdos internos desses caracteres; eu tenho que fazer isso utilizando um método. Assim, existem situações onde é interessante que meus objetos tenham um certo controle sobre o que o programador pode fazer com eles, para que não ocorram problemas. Para isso, temos três tipos de acesso a métodos e atributos.
Quando utilizamos a palavra public, liberamos o acesso do atributo/método para ser utilizado por qualquer um que importe o pacote ou o objeto.
No caso do private, ninguém pode acessar o método/atributo daquele objeto, nem mesmo os objetos daquele pacote ou objetos que herdam suas características. Isso evita que certos métodos sejam acessados diretamente, evitando erros.
Métodos/atributos protected podem ser herdados, mas não alterados. Iremos comentar a respeito de herança mais à frente.
Exemplo:
class exemplo { public metodo1() { ... } private metodo2() { ... } }
Nessa classe, o metodo1 pode ser executado por qualquer outro objeto. O método metodo2 só pode ser executado pelo próprio objeto.
Vamos supor agora que temos que necessitamos de um tipo especial do objeto Empregado, que é o Gerente. O Gerente tem secretária, e a cada aumento ele recebe a mais 0,5% a título de gratificação.
Mas o Gerente continua sendo um empregado; ele também tem nome, seção e salário. Assim, fica mais fácil utilizar a classe Empregado já pronta como um modelo, e aumentar as funcionalidades. Isso é chamado de herança.
Veja a classe Gerente no exemplo abaixo:
class Gerente extends Empregado { public Gerente (String _nome, String _secao, double _salario, String _secretaria) { super (_nome,_secao,_salario); // Aqui eu chamo a super classe do Gerente secretaria = _secretaria; }
public void aumentaSalario (double percentagem) { super.aumentaSalario (percentagem+0,5); }
public String getSecretaria () { return (secretaria); }
public void setSecretaria (String _secretaria) { secretaria = _secretaria; }
private String secretaria; }
O que fizemos aqui foi literalmente nos aproveitarmos do código de outro programa, especializando o objeto Empregado. Adicionamos métodos a essa classe e mesmo alteramos um de seus métodos (aumentaSalario) para refletir uma nova condição.
Uma palavra que apareceu nessa classe foi a super. Ela referencia a classe da qual essa se originou, a classe que foi estendida ou herdada. Assim, super.aumentaSalario invoca o método aumentaSalario da classe Empregado. A classe Gerente poderia ter substituído completamente o método ou fazer alterações, como fizemos.
Assim, é sempre uma boa idéia sempre pensar em construir objetos que possam ser genéricos o suficiente para que possam ser reaproveitados.
Nota: Como referencia para nos auxiliar a determinar se devemos utilizar composição ou herança para construir um objeto, sempre pense:
é para herança (um carro é um veiculo).
contém para composição (um carro contém motor, freio, etc.).
Nota 2: Quando não desejamos que um método ou atributo seja redefinido, utilizamos a palavra reservada final.
O conceito de herança nos leva a discutir outro: o polimorfismo. Podemos traduzir essa palavra pela capacidade de um objeto em saber qual o método que deve executar. Apesar da chamada ser a mesma, objetos diferentes respondem de maneira diferente.
Assim, quando chamamos aumentaSalario da chasse Gerente, é esse método que será executado. Se a classe Gerente não tivesse esse método, o método da classe Empregado seria executado. Caso a classe Empregado também não tivesse esse método, a classe da qual ele veio seria objeto do pedido.
Como exemplo, imagine uma classe chamada Figura. Essa classe tem a habilidade de desenhar a si mesma na tela. Se eu definir uma classe chamada Triangulo que estenda a classe Figura, ela pode usar o método da super classe para desenhar a si mesma, sem necessidade de criar um método apenas para isso.
Usando ainda nosso exemplo de Funcionário e Gerente. Se a classe Funcionário tivesse um método para mudar a seção do funcionário, não seria necessário definir um método igual para a classe Gerente. Entretanto, quando eu invocasse o método Gerente.musaSecao(nova_secao), o objeto saberia como se comportar, pois ele herdou essa “sabedoria” de sua superclasse.
Nota: Como todos os objetos definidos são subclasses de Object , todas as classes que usamos ou definimos, por mais simples que sejam, tem certas capacidades herdadas desta classe. Para maiores detalhes, veja a API.
Exercícios -Implemente o exemplo acima. Altere ou defina métodos usando o mesmo nome (sobrecarga), defina atributos e métodos private e public e teste sua segurança.