A1.1 Prog Ori ObjI

September 23, 2021 | Author: Anonymous | Category: N/A
Share Embed Donate


Short Description

Download A1.1 Prog Ori ObjI...

Description

Curso Técnico em Informática

Programação Orientada a Objetos I

Robson Braga de Andrade Presidente da Confederação Nacional da Indústria

Rafael Lucchesi Diretor do Departamento Nacional do SENAI

Regina Maria de Fátima Torres Diretora de Operações do Departamento Nacional do SENAI

Alcantaro Corrêa Presidente da Federação da Indústria do Estado de Santa Catarina

Sérgio Roberto Arruda Diretor Regional do SENAI/SC

Antônio José Carradore Diretor de Educação e Tecnologia do SENAI/SC

Marco Antônio Dociatti Diretor de Desenvolvimento Organizacional do SENAI/SC

Confederação Nacional da Indústria Serviço Nacional de Aprendizagem Industrial

Curso Técnico em Informática

Programação Orientada a Objetos I Dieison Grumovski

Florianópolis/SC 2011

É proibida a reprodução total ou parcial deste material por qualquer meio ou sistema sem o prévio consentimento do editor.

Autor Dieison Grumovski

Fotografias Banco de Imagens SENAI/SC http://www.sxc.hu/ http://office.microsoft.com/en-us/ images/ http://www.morguefile.com/ http://www.bancodemidia.cni.org.br/

SENAI/SC — Serviço Nacional de Aprendizagem Industrial Rodovia Admar Gonzaga, 2.765 – Itacorubi – Florianópolis/SC CEP: 88034-001 Fone: (48) 0800 48 12 12 www.sc.senai.br

Prefácio Você faz parte da maior instituição de educação profissional do estado. Uma rede de Educação e Tecnologia, formada por 35 unidades conectadas e estrategicamente instaladas em todas as regiões de Santa Catarina. No SENAI, o conhecimento a mais é realidade. A proximidade com as necessidades da indústria, a infraestrutura de primeira linha e as aulas teóricas, e realmente práticas, são a essência de um modelo de Educação por Competências que possibilita ao aluno adquirir conhecimentos, desenvolver habilidade e garantir seu espaço no mercado de trabalho. Com acesso livre a uma eficiente estrutura laboratorial, com o que existe de mais moderno no mundo da tecnologia, você está construindo o seu futuro profissional em uma instituição que, desde 1954, se preocupa em oferecer um modelo de educação atual e de qualidade. Estruturado com o objetivo de atualizar constantemente os métodos de ensino-aprendizagem da instituição, o Programa Educação em Movimento promove a discussão, a revisão e o aprimoramento dos processos de educação do SENAI. Buscando manter o alinhamento com as necessidades do mercado, ampliar as possibilidades do processo educacional, oferecer recursos didáticos de excelência e consolidar o modelo de Educação por Competências, em todos os seus cursos. É nesse contexto que este livro foi produzido e chega às suas mãos. Todos os materiais didáticos do SENAI Santa Catarina são produções colaborativas dos professores mais qualificados e experientes, e contam com ambiente virtual, mini-aulas e apresentações, muitas com animações, tornando a aula mais interativa e atraente. Mais de 1,6 milhões de alunos já escolheram o SENAI. Você faz parte deste universo. Seja bem-vindo e aproveite por completo a Indústria do Conhecimento.

Sumário Conteúdo Formativo Apresentação

9

46 Unidade de estudo 5

68 Unidade de estudo 10

Pacotes, como Organizar suas Classes

11

Interface

69

12 Unidade de estudo 1 Introdução a Programação Orientada a Objeto

47

Seção 1 - Pacotes, como organizar suas classes

72 Unidade de estudo 11 Programação Concorrente e Threads

50 Unidade de estudo 6 Herança

13

Seção 1 - Relação com o mundo real

14

Seção 2 - Relação com o mundo da programação

51

Seção 1 - Reaproveitamento de código

15

Seção 3 - Classes e objetos

54

20

Seção 4 - Métodos e atributos

Seção 2 - Reescrita de métodos

73

56 Unidade de estudo 7 26 Unidade de estudo 2

Polimorfismo

Acessibilidade 57 27

Seção 1 - Controle de acesso

31

Seção 2 - Encapsulamento

Seção 1 - Polimorfismo

60 Unidade de estudo 8 Agregação e Composição

36 Unidade de estudo 3 Construtores 61 37

Seção 1 - Construtores

42 Unidade de estudo 4

64 Unidade de estudo 9 Classes Abstratas

Sobrecarga de Métodos 65 43

Seção 1 - Agregação e composição

Seção 1 - Sobrecarga de métodos

Seção 1 - Classes Abstratas

Seção 1 - Interface

Seção 1 - Programação concorrente e threads

Finalizando

79

Referências

81

8

CURSOS TÉCNICOS SENAI

Conteúdo Formativo Carga horária da dedicação Carga horária: 90 horas

Competências Analisar e implementar os princípios da programação orientada a objetos para solução de problemas computacionais.

Conhecimentos ▪▪ Orientação a objetos: abstração, classes, objetos e instâncias. ▪▪ Comentários. ▪▪ Construtores. ▪▪ Encapsulamento. ▪▪ Herança. ▪▪ Interface de desenvolvimento (IDE). ▪▪ Métodos e atributos.

Habilidades ▪▪ Diferenciar programação orientada a objetos de programação estruturada. ▪▪ Aplicar os conceitos de orientação a objetos. ▪▪ Utilizar interface de desenvolvimento (IDE) de sistemas orientados a objetos.

Atitudes ▪▪ Organização e zelo na utilização de equipamentos. ▪▪ Foco no conteúdo trabalhado. ▪▪ Acesso a sítios relacionados ao tema trabalhado. ▪▪ Organização e limpeza dos ambientes coletivos. ▪▪ Dedicação e empenho nas atividades curriculares e extracurriculares. ▪▪ Capacidade de abstração. ▪▪ Trabalho em equipe. ▪▪ Apresentação de novas soluções para situações problemas. ▪▪ Cumprimento de prazos. ▪▪ Análise crítica de suas produções.

PROGRAMAÇÃO ORIENTADA A OBJETOS I

9

Apresentação Bem-vindo à disciplina de Programação Orientada a Objetos I! Você tem em mãos, um material que foi preparado para assessorar o aperfeiçoamento de seus conhecimentos como futuro profissional da indústria de Tecnologia da Informação (TI). A disciplina de Programação Orientada a Objetos tem como principal objetivo prepará-lo para desenvolver sistemas com um novo paradigma de programação, mais fácil de entender, de manutenir e de desenvolver novas funcionalidades. Para isso, a disciplina apresentará conceitos referentes à programação orientada a objeto, desde declarações simples de variáveis até a utilização de recursos mais complexos, como herança entre classes. Certamente, esse material irá ajudá-lo no desenvolvimento profissional, abordando um tema que é base para a maioria dos grandes sistemas desenvolvidos. Bons estudos!

Dieison Grumovski Dieison Grumovski é graduado em Ciência da Computação pela Universidade do Estado de Santa Catarina (UDESC) e pós-graduado em Engenharia da Produção pela Faculdade de Tecnologia Internacional (FATEC). Atua no SENAI em Joinville como instrutor de cursos técnicos em informática, tendo atuado também como instrutor nos cursos de aprendizagem industrial. Ainda no SENAI trabalhou como pesquisador desenvolvendo um projeto com a tecnologia de identificação por radio frequência (RFID). Atualmente, além das atividades de docência, atua como Analista de Sistemas, trabalhando com tecnologia e inovação na área de Gerenciamento Eletrônico de Documentos (GED) e Gerenciamento de Processos de Negócio (BPM) na empresa TOTVS S.A. em Joinville.

PROGRAMAÇÃO ORIENTADA A OBJETOS I

11

Unidade de estudo 1 Seções de estudo Seção 1 - Relação com o mundo real Seção 2 - Relação com o mundo da programação Seção 3 - Classes e objetos Seção 4 - Métodos e atributos

Introdução a Programação Orientada a Objeto SEÇÃO 1

Relação com o mundo real Muita coisa mudou desde o início do desenvolvimento de software para computadores, entre essas mudanças, estão as próprias linguagens utilizadas para o desenvolvimento desses sistemas. Nesse momento, vale lembrar da programação estruturada, desenvolvida nos anos 60 e que impulsionou a criação de softwares mais complexos, porém, não eram somente os sistemas desenvolvidos que podiam ser mais complexos, os projetos tornavam-se muito grandes e difíceis de serem entendidos e manutenidos, e, é claro, que isso gerava, e ainda gera, altos custo para muitas empresas. Com o objetivo de solucionar esses problemas, a programação orientada a objeto foi criada e tida como resposta aos problemas encontrados na programação estruturada. A programação orientada o objeto, conhecida pelo termo POO, tem como uma de suas características levar para o mundo virtual um pouco do mundo real, e representar os objetos que aqui existem. Essa representação é realizada por meio de classes e atributos, onde a classe representa o objeto em si, e os atributos as suas características.

Para entender melhor o conceito da orientação a objeto, observe como exemplo, um objeto do nosso dia a dia.

Figura 1: Ilustração de objetos Fonte: Locadora (2011)

Nenhum copo da imagem acima é igual ao outro, porém, todos são copos, logo, podemos dizer que todos fazem parte da mesma classe e possuem os mesmos atributos. Nesse caso, temos a classe copo e os seus atributos podem ser, altura, diâmetro da base, diâmetro do bocal, peso e volume. No mundo real, os objetos interagem entre si, o copo precisa de uma mesa para se apoiar, o ser humano utiliza uma cadeira para sentar-se à mesa, e um copo para beber água. Na programação não é diferente, os objetos também interagem entre si, cada um tem um papel e oferece serviços, que são utilizados por outros objetos, e assim o sistema toma forma e se torna funcional. Na próxima seção, você estudará sobre classes e objetos dentro do mundo da programação.

PROGRAMAÇÃO ORIENTADA A OBJETOS I

13

SEÇÃO 2

Relação com o mundo da programação Já fizemos um estudo para entendermos o que são classes e objetos no mundo real, agora, é a vez de entender o que esses termos significam no mundo da informática. Para facilitar, utilizaremos como exemplo para nosso estudo uma videolocadora, identificando algumas classes existentes e seus atributos, que se transformaram em objetos para realizar a troca de mensagens. Quando você vai até a videolocadora com o simples objetivo de locar um filme, você imagina com quantas classes tem contato desde o momento que chega até o momento em que sai com o filme em mãos? Não? Pois essa é uma boa prática para aprender a identificar classes de um sistema. Sabendo disso, vamos praticar! O primeiro ponto é identificar tudo que se precisa para locar uma mídia em uma locadora. Observe:

▪▪ Primeiro, define-se em qual

videolocadora será realizada a locação

▪▪ Definido isso, você se des-

loca até o local e é convidado a fazer um cadastro para que a loja saiba onde você mora, e para que possa entrar em contato, caso seja necessário. Como você é um novo cliente, o atendente solicitará algumas informações para fazer o cadastro, como alguns dados pessoais e endereço.

▪▪ Após a realização do cadastro, você poderá se dirigir até a categoria de filmes do seu interesse e escolher um filme, que pode ser de qualquer tipo de mídia (DRD, blue-ray ou outro).

14

CURSOS TÉCNICOS SENAI

Com base nessa análise, já é possível definir alguns itens como classes obrigatórias do nosso sistema. Veja:

▪▪ ▪▪ ▪▪ ▪▪ ▪▪ ▪▪ ▪▪

Locadora Cliente Endereço Categoria Filme Mídia Funcionário

DICA Para facilitar o estudo e entendimento do material, será utilizado o exemplo da videolocadora. Nos exercícios, será empregado o de uma fábrica de carros e motos. Esse processo vai facilitar o seu desenvolvimento, pois você poderá utilizar os exemplos do material para desenvolver as atividades. E, agora que você entendeu como definir as classes do seu sistema, coloque em prática o conhecimento, realizando o exercício 1 do caderno de atividades práticas.

Após a identificação das classes, é necessário identificar também os seus atributos. Para isso, responda a pergunta: quais são as características dessas classe? Ao mesmo tempo em que se responde a essa pergunta, é possível definir as características necessárias para que o sistema seja desenvolvido. Fazendo isso, têm-se novas classes definidas e prontas. Para entender melhor como responder a essa pergunta, vamos analisar com calma a classe “Filme”, da nossa lista de classes. Pensando em um filme, podemos imaginar várias características, tais

como, nome, tempo de duração, ano de lançamento, categoria, diretor, número de atores, lugar onde foi filmado, tempo de duração para ser criado, valor gasto para o desenvolvimento do filme e tudo mais que possa representar uma informação referente a ele. Mas será que todos esses itens são mesmo necessários para o desenvolvimento do sistema? Claro que não. Para que o dono da locadora ou o próprio cliente precisariam saber quanto custou para criar o filme, no momento em que ele estiver sendo alugado? Essa é uma informação desnecessária, e, pensando dessa forma, a nossa classe Filme ficaria com os seguintes atributos:

▪▪ ▪▪ ▪▪ ▪▪

nome; tempo de duração; ano de lançamento; categoria.

Essas quatro características facilitam a busca do filme dentro da locadora e ainda permitem fornecer aos clientes informações, que normalmente lhes interessam, como, o ano de lançamento e a duração do filme.

DICA Aproveite e defina os atributos para cada classe que você identificou para o seu sistema de fábrica de carros e motos, resolvendo o exercício 2 do caderno de atividades práticas.

Para fazermos uma descrição mais técnica das classes, podemos utilizar a UML para representá-las. É importante lembrar que a UML (Unified Modeling Language) “é uma linguagem utilizada para descre-

ver, de forma gráfica e padronizada, sistemas desenvolvidos utilizando o conceito de orientação a objetos.” (BOOCH; RUMBAUGH; JACOBSON, 2006) Para fazer uma descrição mais técnica das classes utiliza-se a UML, por meio do diagrama de classes, que é representado por um retângulo dividido em três partes, onde a primeira indica a classe, a segunda os atributos e a terceira os métodos. Observe como fica a representação da classe Filme no diagrama de classe UML.

SEÇÃO 3

Classes e objetos Até agora, você aprendeu a definir as classes e seus atributos, tornando possível o desenvolvimento de um sistema para uma videolocadora. Agora, veja como criar essas classes, aplicando a linguagem de programação Java, utilizada no desenvolvimento de sistemas orientados a objetos. Serão usadas as classes já definidas. Você já sabe que uma classe é uma representação de um objeto. Agora, vamos repassar isso para o computador, para que por meio dessa classe, possamos entender e utilizar os objetos criados a partir dela. Para criarmos uma classe, devemos seguir um padrão, que é o seguinte:

[modificadores de acesso] class NomedaClasse{}

Os modificadores de acesso (serão estudados na unidade de estudo seguinte) não são obrigatórios. A palavra reservada class, identifica a classe, seguida por seu nome. Para identificar onde a classe começa e onde termina, utilizam-se as chaves. Elas definem o bloco da classe, que é onde os atributos serão colocados. Sabendo isso, em Java, a classe filme definida anteriormente fica assim:

Figura 2: Diagrama de classe UML para a classe Filme



class Filme { String nome; String categoria; int duracao; int anoLancamento; }

DICA Teste o diagrama de classe, realizando o exercício 3 do caderno de atividades práticas.

Após você ter definido as classes e seus atributos, é a hora de passá-las para o computador em uma linguagem que a máquina entenda. Para isso, utilizaremos a linguagem de programação Java, que é uma linguagem robusta, segura e multiplataforma, capaz de rodar em qualquer máquina, independente do sistema operacional.

Seguindo um padrão mundialmente utilizado, sempre escrevemos nomes de classes com a letra inicial maiúscula e nomes de atributos com a letra inicial minúscula. Quando o nome de um atributo for composto por mais de uma palavra, com exceção da primeira, as demais palavras devem possuir a primeira letra maiúscula, como, o atributo anoLancamento, onde a letra “L” ficou maiúscula. Seguindo o padrão, também não é permitido o uso de acentos ou da “ç”.

O tipo String, utilizado para definir o nome e a categoria da classe Filme, é uma classe do Java. A String pode ser entendida como um vetor de caracteres, ou seja, vários caracteres juntos, agrupados.

Como já temos a classe Filme definida no Java, a partir de agora, tudo será baseado em classes, e é por meio destas que os objetos serão criados.

PROGRAMAÇÃO ORIENTADA A OBJETOS I

15

DICA Aproveite que você acabou de definir a classe Filmes, e realize o exercício 4 do caderno de atividades práticas.

Veja a seguir, a classe Locadora, que servirá apenas para utilizarmos os objetos criados a partir das classes que definimos anteriormente.

class Locadora { public static void main(String[] args) { Filme filme01; filme01 = new Filme(); } }

Perceba que, nesse exemplo, existe o método main. Os métodos serão estudados mais adiante, por enquanto, basta que você entenda que ele é o responsável por iniciar a execução de um programa Java. Note que, no exemplo anterior, as classes e métodos são delimitados por chaves. Após o nome da classe e após o final do método, abre-se uma chave, e no final do exemplo fecham-se duas chaves, que indicam o fim do método main e da classe Locadora, respectivamente.

Como existem os tipos int, float, char, entre outros, todas as classes que criamos, se tornam tipos, e os atributos destes, podem receber objeto dessa classe. No exemplo, criamos uma variável chamada filme01, que é do tipo Filme, e corresponde à classe Filme, que criamos no início dessa seção. O responsável por criar o objeto é o “new”, para isso, basta utilizar essa palavra reservada na frente do nome da classe que deseja criar o objeto, seguido de um abre e fecha parênteses (o significado dos parênteses estudaremos posteriormente). Dessa forma:

new Filme();

Pronto, já sabemos como criar um objeto do tipo Filme. Agora precisamos utilizá-lo, para isso, precisamos armazená-lo em uma variável. Foi por esse motivo que criamos a variável filme01 do tipo Filme. Dessa forma você armazena o objeto no atributo filme01. Veja



16

CURSOS TÉCNICOS SENAI

filme01 = new Filme();

De posse do objeto filme01, você pode acessar os atributos da classe Filme. Entenda como isso é feito.

class Locadora { public static void main(String[] args) { Filme filme01; filme01 = new Filme(); filme01.nome = “Avatar”; filme01.categoria = “Ficção Científica”; filme01.anoLancamento = 2009; filme01.duracao = 166; } }

Para acessar um atributo de um objeto, basta utilizar o ponto como operador de acesso.

Observando o exemplo, é possível perceber que, por meio do ponto, são acessados todos os atributos da classe Filme e atribuídos valores a eles. Nesse momento, o nosso filme é o “Avatar” que pertence à categoria de ficção científica, lançado no ano de 2009, com duração de 166 minutos.

DICA Antes de prosseguir, realize os exercícios 5 e 6 do caderno de atividades práticas.

Em um sistema, pode-se criar quantos objetos forem necessários. No nosso exemplo, precisaremos criar vários, um para cada filme cadastrado no sistema, por isso, basta utiliza a palavra reservada new várias vezes. Observe:

class Locadora { public static void main(String[] args) { Filme filme01; filme01 = new Filme(); filme01.nome = “Avatar”; filme01.categoria = “Ficção Científica”; filme01.anoLancamento = 2009; filme01.duracao = 166; Filme filme02; filme02 = new Filme(); //acessar e setar valores aos atributos } }

PROGRAMAÇÃO ORIENTADA A OBJETOS I

17

Nesse exemplo foram criados dois objetos – filme01 e filme02. Note que antes do texto “acessar e setar valores aos atributos”, foram inseridas duas barras, isso para a linguagem de programação significa comentário, logo, o texto colocado foi apenas um comentário, que ainda faltam acessar e setar os valores dos atributos do objeto filme02. Até o momento, estamos tratando os atributos do tipo Filme como sendo objetos,para facilitar o entendimento, mas saiba que os atributos de tipos de classes não são objetos, eles são uma referência para que o objeto possa ser acessado.

No exemplo a seguir, é correto dizer que o atributo filme01 do tipo Filme, possui uma referência para acessar o objeto. E isso ocorre em todo o Java, sempre teremos atributos referência, nunca objetos.

class Locadora { public static void main(String[] args) { Filme filme01; filme01 = new Filme(); } }

Para facilitar o entendimento, continuaremos chamando de objetos os atributos de referência.

Agora sabendo que os atributos guardam as referências para os objetos, vamos ver o que acontece na memória do computador para armazenar e acessar tais objetos. Observe a figura a seguir:

Figura 3: Referência dos objetos em memória

18

CURSOS TÉCNICOS SENAI

Nesse exemplo, os atributos do tipo Filme chamados filme01 e filme02, fazem referência a locais diferentes na memória, nesses locais estão armazenados os objetos. Por isso, basta termos armazenado o endereço (referência) dos objetos nos atributos para poder encontrá-los, quando necessário. Imagine agora se, por algum motivo, você precisasse atribuir um objeto ao outro, o que aconteceria? Analise o exemplo a seguir.

class Locadora { public static void main(String[] args) { Filme filme01; filme01 = new Filme(); filme01.nome = “Avatar”; filme01.categoria = “Ficção Científica”; filme01.anoLancamento = 2009; filme01.duracao = 166; Filme filme02; filme02 = new Filme(); filme02.nome = “Quem quer ser um milionário”; filme02.categoria = “Drama”; filme02.anoLancamento = 2009; filme02.duracao = 121; filme01 = filme02; System.out.println(filme01.nome); } }

Lembrando que o comando System.out.println serve para imprimir um valor ou frase para o usuário, qual valor você imagina que será impresso? Avatar ou Quem quer ser um milionário? Nesse caso a resposta é simples, o valor exibido será “Quem quer ser um milionário”. Vamos ver na memória o que aconteceu após a execução desse programa. Observando a figura a seguir, note que os dois atributos filme01 e filme02 estão fazendo referência para o mesmo lugar da memória, logo, um dos objetos foi perdido, não temos mais como recuperá-lo.

PROGRAMAÇÃO ORIENTADA A OBJETOS I

19

sempre irão acessar o mesmo objeto quando solicitados, portanto, tanto faz se alterarmos o objeto, utilizando o filme01 ou o filme02. O valor acessado por qualquer um deles sempre será igual, nesse caso o valor impresso será ação.

DICA Faça o teste, realizando o exercício 7 do caderno de atividades práticas.

Figura 4: Referência dos objetos em memória após atribuição

Agora imagine, se fizermos alguma alteração em qualquer um dos objetos, o que irá acontecer? Observe o exemplo:

class Locadora { public static void main(String[] args) { Filme filme01; filme01 = new Filme(); filme01.nome = “Avatar”; filme01.categoria = “Ficção Científica”; filme01.anoLancamento = 2009; filme01.duracao = 166; Filme filme02; filme02 = new Filme(); filme02.nome = “Quem quer ser um milionário”; filme02.categoria = “Drama”; filme02.anoLancamento = 2009; filme02.duracao = 121; filme01 = filme02; filme02.categoria = “Ação”; System.out.println(filme01.categoria); } }

Nesse caso, alteramos a categoria do objeto filme02, e logo abaixo estamos imprimindo o valor da categoria do objeto filme01. O que será impresso para o usuário? Ficção científica, drama ou ação? Na figura anterior, vimos que ao atribuir um atributo referência ao outro, eles farão referência ao mesmo endereço de memória, ou seja, eles

20

CURSOS TÉCNICOS SENAI

Na próxima seção, você aprenderá a criar e invocar métodos criados dentro de suas respectivas classes.

SEÇÃO 4

Métodos e atributos Até o momento você aprendeu a definir uma classe e seus atributos, mas e agora? O que fazer com eles? Dentro de cada classe é preciso definir o que ela faz, ou seja, o seu comportamento. Definindo as funções dentro da própria classe, fica fácil encontrar no programa onde os procedimentos são realizados. Essas funções são chamadas de métodos, que são os responsáveis por realizar as operações com os objetos. Todo método possui uma assinatura, que vai identificá-lo em todo o sistema. Essa assinatura é composta por quatro itens, modificadores de acesso, retorno, nome do método e seus parâmetros. Os modificadores de acesso serão estudados na unidade de estudo seguinte. A estrutura dos métodos fica da seguinte forma:

[modificadores de acesso] retorno nomeDoMetodo(parametros);

Os modificadores de acesso não são obrigatórios. O número de parâmetros não é limitado, podem ser utilizados quantos forem necessários, e caso não o sejam, o método pode não receber parâmetros. Dentro da classe Locadora, que estamos utilizando como exemplo, podemos criar um método para cadastrar um novo filme. Exemplo:

class Locadora { public static void main(String[] args) { Locadora loca = new Locadora(); loca.cadastrarFilme(); } void cadastrarFilme(){ Filme filme01; filme01 = new Filme(); filme01.nome = “Avatar”; filme01.categoria = “Ficção Científica”; filme01.anoLancamento = 2009; filme01.duracao = 166; } }

A palavra reservada void, utilizada antes do nome do método, significa que quando esse método for chamado, não retornará nada como resposta a quem o chamou.

Se lembrarmos da assinatura do método, fica fácil identificar que no método cadastrarFilme não temos controle de acesso, o retorno é void, pois, o nome do método é cadastrarFilme e não possui parâmetros. No exemplo anterior, além do método main, temos também o cadastrarFilme, note que para acessar um método também é utilizado o operador ponto. Para que isso fosse possível, foi criado um objeto do tipo Locadora que foi utilizado para acessar o método cadastrarFilme. Com isso, podemos acessar o método quantas vezes desejar e criar vários filmes, sem precisar repetir o código responsável por setar o valor nos atributos do objeto. Nesse momento entendemos uma das principais características da programação orientada a objetos, o reaproveitamento de código.

Os métodos ainda podem receber valores como parâmetros para realizar operações, da forma como fizemos no exemplo anterior, o método cadastrarFilme só poderia criar objetos do filme Avatar, mas com a passagem de parâmetro, podemos criar qualquer tipo de filme utilizando esse método. O exemplo a seguir mostra isso. PROGRAMAÇÃO ORIENTADA A OBJETOS I

21

class Locadora { public static void main(String[] args) { Locadora loca = new Locadora(); String nome = “Avatar”; String categoria = “Ficção Científica”; int anoLancamento = 2009; int duracao = 166; loca.cadastrarFilme(nome, categoria, anoLancamento, duracao); } void cadastrarFilme(String nome, String categoria, int anoLancamento, int duracao) { Filme filme01; filme01 = new Filme(); filme01.nome = nome; filme01.categoria = categoria; filme01.anoLancamento = anoLancamento; filme01.duracao = duracao; } }

Note que dentro dos parênteses do método, estamos criando alguns atributos para receber valores de quem chama o método. Tais atributos chamamos de parâmetros. Com isso, quem define os valores para os atributos do objeto filme01, que está sendo criado, é quem chama o método e não o próprio método. Além de receber parâmetros, os métodos podem retornar respostas a quem o chamou, isso ocorre sempre no final da execução do método. Para que você entenda melhor, vamos alterar o exemplo anterior para que o método cadastrarFilme, receba valores como parâmetros e retorne uma resposta.

22

CURSOS TÉCNICOS SENAI

class Locadora { public static void main(String[] args) { Locadora loca = new Locadora(); String nome = “Avatar”; String categoria = “Ficção Científica”; int anoLancamento = 2009; int duracao = 166; boolean cadastrado; cadastrado = loca.cadastrarFilme(nome, categoria, anoLancamento, duracao); if(cadastrado == true){ System.out.print(“Filme cadastrado com sucesso.”); } } boolean cadastrarFilme(String nome, String categoria, int anoLancamento, int duracao){ Filme filme01; filme01 = new Filme(); filme01.nome = nome; filme01.categoria = categoria; filme01.anoLancamento = anoLancamento; filme01.duracao = duracao; return true; } }

Nesse exemplo, incluímos antes do nome do método o tipo boolean, isso significa que o método cadastrarFilme agora retorna um valor do tipo boolean. Para que isso aconteça, no final do método foi incluída a expressão “return true;” que é a instrução responsável por enviar a quem chamou o método a resposta “true”, que é do tipo boolean definida antes do nome do método. Dentro do método main, onde chamamos o método cadastrarFilme, criamos um atributo do tipo boolean chamado, cadastrado para receber essa resposta. Para receber a resposta, basta atribuir ao atributo, a chamada do método, dessa forma:

cadastrado = loca.cadastrarFilme(nome, categoria, anoLancamento, duracao);

Depois podemos utilizar essa resposta para imprimir uma mensagem para o usuário do sistema. Observando o exemplo anterior, podemos verificar a existência de uma condição como uso do “if ”, e logo após o comando System.out.println, que é o responsável por imprimir uma mensagem para o usuário. Observe.

PROGRAMAÇÃO ORIENTADA A OBJETOS I

23

if(cadastrado == true){ System.out.print(“Filme cadastrado com sucesso.”); }

Tendo estudado o conceito de métodos, você vai entender agora que os locais onde são criados e, se atribuir valor ou não a um atributo faz diferença. Veja os exemplos e fique atento onde criar e setar valores aos seus atributos. Atributo de instância: significa que o atributo tem seu valor especificado no objeto e não dentro da própria classe. Nesse caso, em geral, o atributo possui um valor diferente em cada objeto representante da classe. Atributo de classe: significa que o atributo tem seu valor especificado na própria classe e é comum a todos os objetos que ela representar. Atributos globais: são os atributos criados dentro do escopo da classe e são acessíveis em toda a classe, inclusive dentro de qualquer método dela. Tanto os atributos de instância, quanto os de classe, são também atributos globais. Atributos locais: são atributos criados dentro de um método ou blocos menores, como estruturas de repetição ou de condição, como for e if respectivamente. Elas só existem dentro daquele bloco, quando o ele acaba, os atributos locais deixam de existir.

Veja um exemplo com os tipos de atributos: class Locadora { //Atributo de instância e global String nome; //Atributo de classe e global String endereço = “Av. 7 de setembro.”; boolean cadastrarFilme(String nome, String categoria, int anoLancamento, int duracao){ //Todos os atributos passados como parâmetros do método são locais (nome, categoria, anoLancamento, duração). //A atributo filme01 é local Filme filme01; filme01 = new Filme(); filme01.nome = nome; filme01.categoria = categoria; filme01.anoLancamento = anoLancamento; filme01.duracao = duracao; return true; } }



24

CURSOS TÉCNICOS SENAI

DICA Agora, treine, realizando o exercício 8 do caderno de atividades práticas.

Nessa unidade de estudos, você aprendeu a definir as classes e seus atributos, também aprendeu a criar e invocar métodos criados dentro de suas respectivas classes, e a definir o comportamento do cada classe. Na próxima unidade, você aprenderá a controlar o acesso e encapsular. Continue atento! Até lá.

PROGRAMAÇÃO ORIENTADA A OBJETOS I

25

Unidade de estudo 2 Seções de estudo Seção 1 - Controle de Acesso Seção 2 - Encapsulamento

Acessibilidade SEÇÃO 1

Controle de acesso Você já parou para pensar nos recursos que são utilizados para proteger você e a sua casa? Normalmente são colocadas cercas, muros altos, cães de guarda, alarmes, grades nas janelas e portas, entre outros, e todos com o mesmo objetivo: controlar o acesso e proteger. Na programação não é diferente, precisamos controlar o acesso às classes, atributos e seus métodos, e, para que isso seja possível, utilizam-se os modificadores de acesso. Como você já viu na unidade de estudo anterior, os controladores de acesso fazem parte das assinaturas dos métodos, mas eles não são utilizados apenas em métodos, podem ser aplicados também a atributos e classes. Eles servem para proteger e restringir o acesso a determinadas partes do nosso sistema. Imagine que você trabalha em uma empresa com muitos funcionários, e que a empresa trabalha com pesquisas científicas, e as descobertas só podem ser conhecidas por algumas pessoas. Uma das medidas tomadas para proteger essas informações, é bloqueando o acesso a algumas salas, e autorizando o acesso de apenas algumas pessoas. Uma forma de fazer isso é com uso de senhas para abrir portas, essas senhas darão mais ou menos poder de acesso aos funcionários.

Os modificadores de acesso também têm esse papel: bloquear o acesso a determinadas classes, métodos e/ou atributos do sistema, de forma que outras classes não tenham acesso a um conteúdo proibido. Para entender melhor, vejamos quais são esses modificadores de acesso e como utilizá-los. Os modificadores de acesso que você estudará são os seguintes: public, protected, private, friendly, abstract, static e final. A seguir é realizada uma explicação baseada no conceito apresentado por Deitel (2005) sobre cada um desses modificadores. Acompanhe.

▪▪ Public: é o mais simples. Ele dá acesso irrestrito, permite que tudo seja acessado de qualquer parte do seu sistema. Qualquer classe, método e atributo, podem ser acessados de qualquer lugar do programa se fizer uso do modificador de acesso public. ▪▪ Protected: permite acesso à

própria classe, às subclasses (classes filhas) e às classes do mesmo pacote.

▪▪ Private: é o modificador mais

restritivo de todos, permite o acesso somente à própria classe, ou seja, os métodos e atributos só podem ser acessados de dentro da classe, nenhuma outra tem acesso.

▪▪ Friendly: é conhecido como default ou package. É o modificador adotado quando não informamos modificadores de acesso. Muitos pensam que quando não informamos, o padrão do Java é o public, mas não é verdade, o modificador de acesso default do Java é o friendly e permite o acesso de todas as classes do mesmo pacote. ▪▪ Abstract: definir, por exem-

plo, um método como abstrato, significa dizer que esse método será desenvolvido nas subclasses, ou seja, na classe onde ele é definido como sendo abstract, vai apenas a assinatura do método. A sua implementação deve ser feita nas classes filhas. Para criar a assinatura de um método usando o abstract, a classe que contém essa assinatura também deve ser abstrata. Classes definidas como sendo abstratas, não podem ser instanciadas.

▪▪ Static: esse modificador define um atributo como sendo da classe e não da instância da classe. Dessa forma, a cada novo objeto criado (nova instância), não será feita uma cópia desse atributo, ele será compartilhado por todas as instâncias da classe. Com isso, se uma instância realizar alguma alteração no valor do atributo, essa mudança será aplicada a todas as demais.

PROGRAMAÇÃO ORIENTADA A OBJETOS I

27

▪▪ Final: quando esse modificador é aplicado a um atributo, ele não pode ter seu valor alterado, tornando-se uma constante. Quando aplicado a uma classe, esta não pode ser herdada, e quando aplicado a um método, o método não pode ser redefinido. Agora que você já conhece os principais modificadores de acesso, como podemos utilizá-los para proteger nosso sistema de locadora? Veja alguns exemplos. Na nossa classe Locadora, exemplificada a seguir, não estamos utilizando nenhum tipo de modificador de acesso, exceto no método main, que é o método com a assinatura padrão utilizado pelo Java para dar início à execução do programa. Se quiséssemos que a classe Locadora e seus métodos fossem accessíveis de qualquer lugar do sistema, qual modificador de acesso deveríamos utilizar? Acertou, se você respondeu public.

class Locadora { public static void main(String[] args) { Locadora loca = new Locadora(); String nome = “Avatar”; String categoria = “Ficção Científica”; int anoLancamento = 2009; int duracao = 166; boolean cadastrado; cadastrado = loca.cadastrarFilme(nome, categoria, anoLancamento, duracao); if(cadastrado == true){ System.out.print(“Filme cadastrado com sucesso.”); } } boolean cadastrarFilme(String nome, String categoria, int anoLancamento, int duracao){ Filme filme01; filme01 = new Filme(); filme01.nome = nome; filme01.categoria = categoria; filme01.anoLancamento = anoLancamento; filme01.duracao = duracao; return true; } }

Para torná-la toda pública, é necessário acrescentar a palavra public em dois locais: no início da classe e antes do retorno do método. Fazendo essas mudanças, nosso exemplo ficaria da seguinte forma.

28

CURSOS TÉCNICOS SENAI

public class Locadora { public static void main(String[] args) { Locadora loca = new Locadora(); String nome = “Avatar”; String categoria = “Ficção Científica”; int anoLancamento = 2009; int duracao = 166; boolean cadastrado; cadastrado = loca.cadastrarFilme(nome, categoria, anoLancamento, duracao); if(cadastrado == true){ System.out.print(“Filme cadastrado com sucesso.”); } } public boolean cadastrarFilme(String nome, String categoria, int anoLancamento, int duracao){ Filme filme01; filme01 = new Filme(); filme01.nome = nome; filme01.categoria = categoria; filme01.anoLancamento = anoLancamento; filme01.duracao = duracao; return true; } }

Sabendo onde aplicar os modificadores, fica fácil utilizar os demais. Nos locais onde colocamos a palavra public, basta substituir pelo modificador necessário, podendo ser protected, private ou abstract. Os modificadores static e final são utilizados em conjunto com os demais. Para entender melhor essa utilização conjunta, vamos utilizar a nossa classe Filme para exemplificar.

class Filme { String nome; String categoria; int duracao; int anoLancamento; }

Na classe Filme apresentada, não temos uso de nenhum modificador de acesso. Imagine que queremos tornar essa classe pública, porém, seus atributos devem ser protegidos de qualquer outra classe do sistema, e outro diferencial, o ano do filme deve ser compartilhado por todas as instâncias dessa classe. Para fazer isso tudo, precisamos em primeiro lugar tornar a classe pública, e, para isso, basta incluir a palavra public no início da classe, depois, precisamos tornar os atributos protegidos de todas as outras classes do sistema, para isso basta incluir a palavra private antes da declaração de todos os atributos e por último, tornar o ano de lançamento do filme compartilhado por todas as instâncias, incluindo o modificador de acesso static antes do private. Fazendo todas essas mudanças corretamente, teremos como resultado a classe Filme da seguinte forma:

public class Filme{ private String nome; private String categoria; private int duracao; private static int anoLancamento; }

PROGRAMAÇÃO ORIENTADA A OBJETOS I

29

Com o uso do modificador static no atributo anoLançamento, todas as instâncias da classe filme terão o mesmo valor sempre para esse atributo. Exemplo: public class Filme{ private String nome; private String categoria; private int duracao; private static int anoLancamento; public void testeFilme(){ Filme filme01 = new Filme(); Filme filme02 = new Filme(); filme01.anoLancamento = 2011; filme02.anoLancamento = 2010; System.out.println(“Ano de lançamento = “ + filme01.anoLancamento); System.out.println(“Ano de lançamento = “ + filme02.anoLancamento); }

}

No exemplo anterior, temos na classe Filme um método de teste chamado testeFilme(), que está sendo utilizado apenas para demonstrar o uso do modificador de acesso. Esse método cria dois objetos, ou seja, duas instâncias da classe Filme. Após criar os objetos serão atribuídos valores ao atributo anoLancamento de ambos os objetos. Logo após é impresso o valor de ambos os atributos dos objetos. Você sabe quais valores serão impressos? Lembrando que o atributo em questão utiliza o modificador static, você está certo se responder que em ambas as frases impressas aparecerá o ano de 2010. E você sabe por que isso ocorreu? Porque o conceito de static é de que o atributo é compartilhado por todas as instâncias da classe, isto é, se uma instância tem o valor 2010, todas as outras também o terão, com isso sempre o último valor atribuído ao atributo será utilizado por todas as instâncias. Foi preciso criar um método de teste dentro da própria classe Filme, para que pudéssemos acessar os atributos dela, isso foi necessário devido ao fato de que todos foram declarados como private, e por isso só podem ser acessados de dentro da própria classe. Da mesma forma que o modificador static é utilizado em conjunto com outros modificadores, o modificador final também deve ser utilizado em conjunto. Confira um exemplo de uso do modificador final. public class Filme{ private String nome; private String categoria; private int duracao; private final int anoLancamento = 2011; }

30

CURSOS TÉCNICOS SENAI

O uso do modificador final obriga que um valor seja atribuído ao atributo no momento da criação, por isso precisamos criá-lo e conferir-lhe o valor 2011. Feito isso, esse atributo não poderá mais ser alterado, sempre vai valer 2011. E o que acontece se tentarmos atribuir valor a um atributo do tipo final como mostrado a seguir?



filme01.anoLancamento = 2011; filme02.anoLancamento = 2010;

Se você respondeu que irá gerar um erro no momento de compilar o programa, você acertou. O compilador Java vai identificar que uma operação incorreta está tentando ser executada e irá gerar um erro, não sendo possível executar o programa. Após termos estudado os modificadores de acesso, veremos outra forma de tornar nosso sistema mais acessível e seguro, sem esquecer os modificadores de acesso.

DICA Antes de estudar o encapsulamento, realize os exercícios 9, 10 e 11 do caderno de atividades práticas.

SEÇÃO 2

Encapsulamento O objetivo de se utilizar o encapsulamento, no desenvolvimento de sistemas, é agrupar as funcionalidades referentes a um objeto em um único lugar, garantindo a segurança no acesso às informações, facilitando a busca dos programadores por métodos dentro do sistema, seja para consultar ou para realizar manutenções. Imagine que você precisa alterar o método onde é realizado o cadastro de filmes, em qual classe você procuraria? Se não existisse o encapsulamento você poderia ficar perdido, e poderiam existir vários locais no seu sistema que realizam essa operação, mas com o encapsulamento o cadastro de filmes é feito por uma única classe, a Locadora, onde o funcionário da locadora é que realiza o cadastro de todos os filmes. É por isso que esse método foi colocado na classe Filme.

A ideia do encapsulamento é também fechar o nosso sistema, de forma que quem for utilizar os métodos e atributos saiba para que eles servem, e não o que eles fazem ou o que é feito com eles internamente.

PROGRAMAÇÃO ORIENTADA A OBJETOS I

31

Imagine que você irá fazer um cadastro de um novo filme, você precisa saber o que o método de cadastro faz internamente? Não. Você só precisa saber que ele vai fazer o cadastro e não como ele faz. Dessa forma nosso sistema fica mais organizado e com isso mais fácil de entender. Se algum dia outro programador que não participou desde o início do desenvolvimento do sistema precisar realizar uma modificação em algum método, ele não terá tanta dificuldade para encontrar e manutenir as funcionalidades do sistema. Para auxiliar na questão do acesso aos atributos, é comum na orientação a objeto a criação de métodos get e set. Esses métodos são utilizados para dar acesso a atributos declarados como private. Você deve pensar sempre em dar acesso e não retirar acesso aos atributos. O que isso quer dizer? Como padrão crie sempre os atributos das classes como private, assim ninguém vai conseguir acessá-los de fora da classe. Caso você queira permitir o acesso a algum desses atributos, utilize os métodos set e get.

Mas o que são métodos set e get? Os métodos set e get são responsáveis por colocar valor em um atributo ou recuperar o valor de um atributo respectivamente.

Defini-se, que por padrão, sempre se criará os atributos de classes como sendo privados. Portanto, a nossa classe Filme fica assim:

public class Filme{ private String nome; private String categoria; private int duracao; private int anoLancamento; }

Dessa forma ninguém terá acesso aos atributos dessa classe a não ser ela mesma. Agora você concorda que assim, a classe Filme, não terá utilidade alguma, pois é a classe Locadora que fazia uso desses atributos, e com eles declarados como private, ela não terá mais acesso. É em situações como esta que entra o uso dos métodos get e set. Devemos criar os métodos de acordo com a necessidade do sistema, para liberar o acesso necessário aos atributos. Não é obrigatória a criação dos dois métodos, set e get, eles devem ser criados de acordo com a necessidade do sistema.

32

CURSOS TÉCNICOS SENAI

No nosso exemplo, necessitamos liberar o acesso a todos os atributos, logo, precisamos criar os métodos get e set para todos os atributos. Fazendo isso, a classe Filme ficará assim:

public class Filme{ private String nome; private String categoria; private int duracao; private int anoLancamento; public String getNome() { return nome; } public void setNome(String nome) { this.nome = nome; } public String getCategoria() { return categoria; } public void setCategoria(String categoria) { this.categoria = categoria; } public int getDuracao() { return duracao; } public void setDuracao(int duracao) { this.duracao = duracao; } public int getAnoLancamento() { return anoLancamento; } public void setAnoLancamento(int anoLancamento) { this.anoLancamento = anoLancamento; } }

Observando os métodos set e get, identificamos um padrão para o nome dos métodos, utilizando sempre o set ou get seguido do nome do atributo com letra maiúscula. Para o atributo nome os métodos ficam assim:

public String getNome() { return nome; } public void setNome(String nome) { this.nome = nome; }

Observe que o método getNome é responsável por retornar o valor do atributo nome, enquanto que o setNome recebe como parâmetro um valor para ser salvo no atributo nome, e essas são as suas funções, retornar e salvar um valor em um determinado atributo.

PROGRAMAÇÃO ORIENTADA A OBJETOS I

33

No método setNome você pode observar o uso de um novo operador, o this, que é utilizado para indicar que estamos acessando o atributo da classe e não o atributo que está sendo passado como parâmetro no método, pois ambos têm o mesmo nome. A palavra chave “this” é utilizada para indicar que estamos acessando o atributo ou método da classe em que estamos trabalhando.

O uso do this não é obrigatório, porém é altamente recomendado, pois facilita a leitura do código fonte pelos programadores. Para retirá-lo do método set.nome é preciso trocar o nome do atributo que está sendo passado como parâmetro. Confira o exemplo:

public void setNome(String param) { nome = param; }

Com o uso dos métodos set e get, você pode controlar se outras classes terão acesso aos atributos ou não. Se você pretender dar acesso apenas a gravação de dados nos atributos, basta criar apenas o método set na sua classe. Porém, se você quer permitir que outras classes apenas recuperem o valor dos atributos, basta criar na sua classe o método get. Agora, com os métodos set e get criados e entendidos, temos que alterar também a forma de acessar os atributos. Não é mais possível acessá-los diretamente como estávamos fazendo até agora, daqui em diante teremos que chamar os métodos set e get, como mostra o exemplo a seguir:

public class Locadora{ public static void main(String[] args) { Filme filme01; filme01 = new Filme(); //salvando informações filme01.setNome(“Avatar”); filme01.setCategoria(“Ficção Científica”); filme01.setAnoLancamento(2009); filme01.setDuracao(166); //pegando informações System.out.println(“Nome: “ + filme01.getNome()); System.out.println(“Categoria: “ + filme01.getCategoria()); System.out.println(“Ano de lançamento: “ + filme01.getAnoLancamento()); System.out.println(“Duração: “ + filme01.getDuracao()); } }

34

CURSOS TÉCNICOS SENAI

DICA Realize os exercícios do 12 ao 15 do caderno de atividades práticas e perceba que com o uso dos modificadores de acesso, em conjunto com a criação dos métodos set e get, têm-se classes muito mais seguras e organizadas.

Agora que você já sabe criar os controles de acesso e encapsular, está pronto para aprender o porquê de criar dessa maneira. Então, prepare-se e bom estudo!

PROGRAMAÇÃO ORIENTADA A OBJETOS I

35

Unidade de estudo 3 Seções de estudo Seção 1 - Construtores

Construtores SEÇÃO 1

Construtores Se você observar a criação de um objeto, perceberá algo parecido com a chamada de um método, veja no exemplo a classe Locadora: public class Locadora { public static void main(String[] args) { Locadora loca = new Locadora(); String nome = “Avatar”; String categoria = “Ficção Científica”; int anoLancamento = 2009; int duracao = 166;boolean cadastrado; cadastrado = loca.cadastrarFilme(nome, categoria, anoLancamento, duracao); if(cadastrado == true){ System.out.print(“Filme cadastrado com sucesso.”); } } public boolean cadastrarFilme(String nome, String categoria, int anoLancamento, int duracao){ Filme filme01; filme01 = new Filme(); filme01.nome = nome; filme01.categoria = categoria; filme01.anoLancamento = anoLancamento; filme01.duracao = duracao; return true; } }

Note que no método main criamos um objeto do tipo Locadora e no método cadastrarFilme criamos um objeto do tipo Filme. A criação é realizada com o uso do new, a expressão que representa o objeto é a seguinte:

new Filme();

Sempre se utiliza o nome da classe seguido de abre e fecha parênteses. Você sabe por que é feito isso? É como se fosse chamado um método Filme, pois toda chamada de método, também abre e fecha parênteses.

PROGRAMAÇÃO ORIENTADA A OBJETOS I

37

Realmente, sempre que se utiliza o new é criado um novo objeto, e para criar esse objeto é necessário chamar o método construtor da classe que se deseja criar.

“Um método construtor nada mais é do que um método com o mesmo nome da classe, exatamente o mesmo nome, obedecendo inclusive as letras maiúsculas e minúsculas” (DEITEL, 2005, p. 68). Veja o exemplo de como ficaria a classe Filme com o método construtor:

public class Filme{ private String nome; private String categoria; private int duracao; private int anoLancamento; public Filme(){ System.out.println(“Filme Criado!”); } // métodos set e get }

Observando o exemplo você pode pensar que, como não tínhamos os métodos construtores estávamos fazendo errado, mas não estávamos. Mesmo sem serem criadas, todas as classes possuem, por definição, um método construtor vazio. Assim:

Filme(){ }

Por isso, mesmo que você não crie o método construtor dentro da classe, acredite, ele esta lá! Agora você pode ter ficado com outra dúvida: se o Java cria como padrão um método construtor para todas as classes, por que você precisa criá-los? Sempre que se cria um método construtor para uma classe, o método construtor default deixa de ser utilizado, logo o seu método construtor se torna o principal da classe. Imagine que antes de tudo, o seu método será chamado e você poderá fazer qualquer operação nesse momento, você pode iniciar atributos, fazer chamadas a outros métodos, enfim, definir como seu objeto será criado. No exemplo a seguir, foi criado um método construtor que, antes de criar o objeto do tipo Filme, inicializa o atributo nome com um valor qualquer. Veja:

38

CURSOS TÉCNICOS SENAI

public class Filme{ private String nome; private String categoria; private int duracao; private int anoLancamento; public Filme(){ this.nome = “Avatar”; } }

// métodos set e get

Fazendo isso, sempre que um objeto do tipo filme for criado, ele já será criado com o nome Avatar. Fazendo dessa forma, não fica muito usual, uma vez que não existe apenas o filme Avatar, mas sim vários filmes que serão cadastrados. Então que outra forma de setar valor para esse atributo pode ser usada? O método construtor aceita a passagem de parâmetros. Observe o exemplo:

public class Filme{ private String nome; private String categoria; private int duracao; private int anoLancamento; public Filme(String nome){ this.nome = nome; } }

// métodos set e get

Nesse caso, podemos garantir que sempre que um objeto do tipo filme for criado, ele possuirá um nome, pois isso é feito no seu construtor, e se um nome não for passado a ele, o objeto não será criado. A forma de criar esse objeto agora mudou um pouco, devido a passagem do parâmetro, na nossa classe Locadora a criação do objeto Filme fica conforme o exemplo a seguir:

PROGRAMAÇÃO ORIENTADA A OBJETOS I

39

public class Locadora { public static void main(String[] args) { Locadora loca = new Locadora(); String nome = “Avatar”; String categoria = “Ficção Científica”; int anoLancamento = 2009; int duracao = 166; boolean cadastrado; cadastrado = loca.cadastrarFilme(nome, categoria, anoLancamento, duracao); if(cadastrado == true){ System.out.print(“Filme cadastrado com sucesso.”); } } public boolean cadastrarFilme(String nome, String categoria, int anoLancamento, int duracao){ Filme filme01; filme01 = new Filme(nome); filme01.categoria = categoria; filme01.anoLancamento = anoLancamento; filme01.duracao = duracao; return true; } }

Observe que nosso método main não foi alterado, apenas o método cadastrarFilme sofreu alterações. A criação do objeto Filme agora recebeu um parâmetro, correspondente ao nome do Filme e não é mais necessário setar valor para o atributo nome da classe Filme, uma vez que agora isso é feito dentro do método construtor. Apesar de ser chamado de método construtor, ele não é um simples método. Pode-se dizer que é um método especial, pois não pode possuir retorno e só pode ser chamado no momento de criação de um objeto.

Uma classe pode ter quantos métodos forem necessários para sua utilização, e não é diferente para métodos construtores, que permitem mais de um método construtor em uma mesma classe. Veja o exemplo:

40

CURSOS TÉCNICOS SENAI

public class Filme{ private String nome; private String categoria; private int duracao; private int anoLancamento; public Filme(String nome){ this.nome = nome; } public Filme(String nome, String categoria){ this.nome = nome; this.categoria = categoria; } }

// métodos set e get

Nesse caso criamos dois métodos construtores, onde um recebe apenas o nome do filme como parâmetro, e o segundo recebe o nome e a categoria. Dependendo da necessidade, pode-se utilizar um ou outro para criar nossos objetos do tipo Filme e, para utilizá-los basta fazer da seguinte forma: Filme filme01 = new Filme(nome); ou Filme filme01 = new Filme(nome, categoria);

Os métodos construtores são muito importantes, pois com eles é possível controlar e definir como um objeto será criado, e se será realizada alguma operação no momento de sua criação.

DICA Os exercícios 16, 17 e 18 do caderno de atividades práticas são sobre os métodos construtores. Que tal resolvê-los e testar o que acabou de aprender?

Você viu que é possível criar métodos com o mesmo nome em uma mesma classe, utilizando os métodos construtores, que possuem o mesmo nome e podem ser criados mais de um na mesma classe. Na próxima unidade de estudos você estudará as sobrecargas de métodos. Até lá!

É possível também chamar um construtor de dentro de outro, lembrando do conceito do método construtor que diz que ele só pode ser chamado durante a criação do objeto, e, como está sendo criado dentro de outro método construtor então pode ser chamado de dentro deste. Observe o exemplo.

public class Filme{ private String nome; private String categoria; private int duracao; private int anoLancamento; public Filme(String nome){ this.nome = nome; } public Filme(String nome, String categoria){ // Chamada do primeiro método construtor this(nome); this.categoria = categoria; } }

// métodos set e get

PROGRAMAÇÃO ORIENTADA A OBJETOS I

41

Unidade de estudo 4 Seções de estudo Seção 1 - Sobrecarga de métodos

Sobrecarga de Métodos SEÇÃO 1

Sobrecarga de métodos O fato de criarmos métodos com o mesmo nome em uma mesma classe é chamado de sobrecarga de métodos, ou ainda de overloading. O que não pode existir em uma mesma classe, são métodos com assinaturas iguais. O que isso quer dizer? Quer dizer que não se pode ter dois métodos com o mesmo nome, e com os mesmos tipos e números de parâmetros. Observe o diagrama a seguir para entender melhor o conceito de sobrecarga.

Figura 5: Diagrama de classe UML com sobrecarga de métodos

Nesse diagrama apresentado pode-se entender melhor esse conceito de sobrecarga. Há três métodos, todos com o mesmo nome, porém, com algumas sobrecargas: os tipos dos parâmetros entre o primeiro e o segundo método e a quantidade de parâmetros passados no quarto método. A sobrecarga de métodos cadastrarFilme ficaria da seguinte forma se desenvolvido na linguagem Java:

PROGRAMAÇÃO ORIENTADA A OBJETOS I

43

public class Locadora { public static void main(String[] args) { Locadora loca = new Locadora(); String nome = “Avatar”; String categoria = “Ficção Científica”; int anoLancamento = 2009; int duracao = 166; boolean cadastrado; cadastrado = loca.cadastrarFilme(nome, categoria, anoLancamento, duracao); if(cadastrado == true){ System.out.print(“Filme cadastrado com sucesso.”); } } public boolean cadastrarFilme(String nome, String categoria, int anoLancamento, int duracao){ Filme filme01; filme01 = new Filme(nome); filme01.categoria = categoria; filme01.anoLancamento = anoLancamento; filme01.duracao = duracao; return true; } public boolean cadastrarFilme(String nome, String categoria, String anoLancamento, String duracao){ //implementação do método } public boolean cadastrarFilme(String nome){ //implementação do método } }

DICA Como os métodos terão o mesmo nome e, provavelmente, serão utilizados para realização de tarefas semelhantes, é importante escolher um nome mais apropriado que identifique todas as tarefas de modo a não gerar confusão no momento de sua utilização.

E como saber qual método está sendo chamando no momento da execução quando há nomes repetidos? Você não precisa se preocupar com isso pois, quem define, é o compilador, levando em consideração as diferenças dos métodos para utilizá-los de acordo com suas características, por exemplo:

boolean retorno = cadastrarFilme(“Avatar”, “Ficção Científica”, “2009”, “166”);

44

CURSOS TÉCNICOS SENAI

Nesse caso, temos os quatro parâmetros como sendo do tipo String. O compilador identificou e utilizou o segundo método criado na classe Locadora, que é o que recebe como parâmetro os quatro parâmetros do tipo String. Você sabe que método da classe locadora seria chamado se, ao invés do exemplo anterior, fosse feito da seguinte maneira?

boolean retorno = cadastrarFilme(“Avatar”);

Neste caso seria chamado o último método, pois, ele é o único que recebe apenas um parâmetro. Tenha bastante cuidado ao fazer sobrecarga com o mesmo número de parâmetros, pois o compilador diferencia o tipo dos parâmetros, e não o nome deles.

O exemplo a seguir não caracteriza uma sobrecarga. public boolean cadastrarFilme(String nome, String categoria, String anoLancamento, String duracao){ //implementação do método } public boolean cadastrarFilme(String nome, String categoria, String ano, String tempo){ //implementação do método }

Nesse exemplo apresentado, foram alterados os nomes de dois parâmetros, de anoLancamento para ano, e de duração para tempo. Essa mudança não caracteriza uma sobrecarga, e o seu programa não irá funcionar, pois existem dois métodos exatamente iguais, e isso não é permitido.

DICA Utilizando o caso da fábrica de carros e motos, teste a sobrecarga, realizando os exercícios 19 e 20 do caderno de atividade práticas.

Na próxima unidade de estudos você aprenderá como organizar as suas classes por meio de pacotes. Prepare-se!

PROGRAMAÇÃO ORIENTADA A OBJETOS I

45

Unidade de estudo 5 Seções de estudo Seção 1 - Pacotes, como organizar suas classes

Pacotes, como Organizar suas Classes SEÇÃO 1

Pacotes, como organizar suas classes Para falar dos pacotes em Java, vamos fazer uma analogia com as pastas que você cria costumeiramente no sistema operacional. Imagine que você possua apenas uma pasta em todo seu computador, como você faria para organizar suas coisas? Certamente colocaria suas músicas em uma pasta, seus trabalho da disciplina de POO em outra pasta, e assim por diante. Agora, imagine se essa separação de pastas não fosse possível e tudo tivesse que ficar em um mesmo lugar, tudo misturado. Seria horrível, não é mesmo? Ainda bem que podemos organizar tudo em diretórios, fica muito mais fácil encontrar os documentos. Agora pense na seguinte situação: você e alguns amigos foram fazer um passeio e tiraram várias fotos com a sua câmera digital, e agora todos os seus amigos estão pedindo uma cópia dessas fotos. Você pode simplesmente copiar a pasta de uma só vez e repassá-la aos seus amigos – o que é muito fácil – ou você pode ficar procurando as fotos em meio a outros documentos e copiar, foto por foto, com o risco de esquecer alguma pelo caminho.

Na programação isso não é diferente. Não vamos criar todas as nossas classes dentro de um único diretório, mas sim, dividi-las de acordo com suas funcionalidades e necessidades do projeto. Os diretórios dentro da programação são chamados de pacotes, ou package. Imagine que temos uma classe salva dentro do seguinte diretório no sistema operacional:

\br\com\poo\locadora

Isso significa que nossa classe está dentro do seguinte package:

br.com.poo.locadora

Observe que na estrutura de diretórios do sistema operacional, os nomes das pastas são separados por barras “\”, e os packages são divididos por pontos “.”. Da mesma formaque existem padrões, no momento de criar nomes de classes, métodos e variáveis, existe um padrão para criação de pacotes, nesse caso, todos os pacotes devem ser escritos apenas com letras minúsculas, independente se os nomes são compostos por mais de uma palavra. Deve-se referenciar o pacote, onde a classe está gravada e no início desta, informando sempre a palavra package seguida do caminho completo do pacote. Para entender melhor, veja esse exemplo: imagine que a classe Pessoa encontrasse dentro do pacote “br.com.poo.entidade”. Tal classe ficaria assim:

PROGRAMAÇÃO ORIENTADA A OBJETOS I

47

package br.com.poo.entidade.Pessoa; public class Pessoa { private String nome; private String telefone; private String rg; private String cpf; private String estadoCivil; private String sexo; //implementação dos métodos }

Dentro de um mesmo pacote, podem estar quantas classes forem necessárias, e todas têm acesso direto umas as outras - é o que estava sendo feito até o momento - pois todas estavam em um mesmo pacote. Se quiséssemos acessar a classe Pessoa, de dentro da classe Locadora, imaginando que nesse momento elas estão no mesmo pacote, poderíamos fazer um acesso direto por meio de “Pessoa pessoa = new Pessoa();”. Confira:

package br.com.poo.entidade.Locadora; public class Locadora{ public static void main(String[] args) { Pessoa pessoa = new Pessoa(); pessoa.getEndereco().setBairro(“Bom Retiro”); pessoa.getEndereco().setCep(“89222-365”); //... } }

Imagine que colocamos a classe Locadora dentro do pacote br.com.poo. locadora. Como fazer para acessar a classe Pessoa de dentro da classe Locadora? Como elas estão em pacotes diferentes, não há mais o acesso direto entre as classes, como fazer para acessar as classes que não estão no mesmo pacote? Para que funcione corretamente, pode-se informar o caminho completo do pacote da classe que se quer acessar, fazendo da seguinte forma:

br.com.poo.entidade.Pessoa pessoa = new br.com.poo.entidade.Pessoa();

Fazendo dessa forma, não fica nem um pouco elegante o código fonte, e toda vez que se quiser fazer referência à classe Pessoa, seria necessário escrever o caminho completo. Nada prático, não acha?

48

CURSOS TÉCNICOS SENAI

Para resolver isso, o Java possui uma palavra reservada chamada import, que serve para importar um pacote para dentro da classe onde o import foi utilizado. Com isso não existe a necessidade de digitar todo o caminho do pacote de uma classe toda vez que desejarmos fazer referência a ela. Com a classe Locadora em outro diretório e utilizando o import para fazer acesso à classe Pessoa, e com a classe Locadora em outro diretório, esta ficaria da seguinte forma:

package br.com.poo.locadora.Locadora; import br.com.poo.entidade.Pessoa; public class Locadora{ public static void main(String[] args) { Pessoa pessoa = new Pessoa(); pessoa.getEndereco().setBairro(“Bom Retiro”); pessoa.getEndereco().setCep(“89222-365”); //... } }

Note que agora, o package da classe mostra que o pacote da classe Locadora não é mais o “entidade”, e sim o pacote “locadora”.

package br.com.poo.locadora.Locadora;

Já o uso do import, indica que pode-se utilizar a classe Pessoa, que está dentro do pacote “br.com.poo.entidade” diretamente, como se a classe estivesse dentro do mesmo pacote. A instrução que permite isso é:

import br.com.poo.entidade.Pessoa;

Fazendo uso desse recurso, continua-se tendo acesso a todas as classes, independentemente delas estarem ou não no mesmo pacote. É possível, também, importar todas as classes de um pacote de uma só vez. Para isso, basta utilizar o “*”, que indica que qualquer classe, em um pacote, pode ser acessada. Por exemplo:

import br.com.poo.entidade.*;

Nesse caso, se permite o acesso a todas as classes que estão dentro do pacote entidade.

O import vale também para classes externas ao projeto, por exemplo, se quisermos utilizar uma classe do Java, dentro de alguma das classes, como a ArrayList do Java, que implementa uma lista, para que se tenha acesso a essa classe, será necessário, obrigatoriamente, fazer um import dela para a classe em que se quer utilizá-la. Portanto, o import ficaria da seguinte forma:

import java.util.ArrayList;

Fazendo isso, poderíamos utilizar uma classe que não está no projeto, mas está implementada diretamente pelo próprio Java. Note que, nesse caso, importamos apenas a classe ArrayList, que está dentro do pacote “util” do Java. Não é obrigatório importar um pacote inteiro, se você utilizar somente uma classe. Nessa unidade, você viu que podemos importar todo um pacote, o que dá acesso a todas as classes do pacote, ou utilizar o “*” para importar todas as classes de uma só vez. Lembre-se que é importante deixar o sistema o mais limpo possível, ou seja, importe somente as classes que serão utilizadas para não existir dúvidas sobre as classes corretas. No sistema, na classe Locadora, seria importada apenas a classe Pessoa, que é a que nos interessa ter acesso. Isso é o correto a ser feito.

Na próxima unidade, você aprenderá como reaproveitar códigos e reescrever métodos, mas antes de continuar, realize o exercício 21 do caderno de atividades práticas.

PROGRAMAÇÃO ORIENTADA A OBJETOS I

49

Unidade de estudo 6 Seções de estudo Seção 1 - Reaproveitamento de código Seção 2 - Reescrita de métodos

Herança SEÇÃO 1

Reaproveitamento de código Os sistemas, de um modo geral, evoluíram muito nos últimos anos e para que essa evolução acontecesse, foi necessário escrever muitas linhas de código fonte. Agora, imagine classes imensas e projetos com centenas de classes; será que tudo isso era mesmo necessário? Será que não há uma forma de reutilizar partes do código fonte e tornar o sistema mais simples? Essa é uma das vantagens de se utilizar a herança. Antes de entender o que é a herança na programação, pense na sua vida, o que é herança? Pense em características genéticas, já lhe disseram como você é parecido com seu pai ou com sua mãe? Pois bem, isso é herança, seus pais herdaram características do seus avós, e você herdou características dos seus pais. A figura a seguir representa a herança genética, que o filho herda características do pai.

Tendo claro o conceito de herança, já podemos falar de forma técnica. Com a herança não é preciso repetir atributos ou métodos, ou seja, não é preciso reescrevê-los, podendo simplesmente utilizar os atributos de outras classes que já o desenvolveram. Porém, para utilizar a herança, não é simplesmente sair herdando toda e qualquer classe. Estas precisam ter alguma relação. Vamos buscar novamente o exemplo da locadora, para entender melhor esse conceito. Definimos na primeira unidade de estudo que precisaríamos de uma classe para definir um cliente, e uma classe para definir um funcionário. Mas o que essas duas classes têm em comum? Tanto um cliente como um funcionário são pessoas, logo, terão atributos em comum. Os atributos que a classe Cliente e a classe Funcionário tiverem em comum, você pode isolar em uma terceira. Assim não será necessário duplicar as informações, o código fica mais centralizado, com isso o sistema fica mais fácil de entender e de manutenir. Observe a figura a seguir, para entender melhor como ficaria o nosso exemplo, utilizando o conceito de herança.

Figura 6: Diagrama exemplificando a herança genética

Figura 7: Herdando da classe Pessoa

PROGRAMAÇÃO ORIENTADA A OBJETOS I

51

Como funcionários e clientes são pessoas, criamos uma classe chamada Pessoa, para centralizar nela todos os atributos comuns dessas classes. Observando a figura 7, se pode identificar os atributos nome, telefone, rg, cpf, estadoCivil e sexo, como sendo os atributos comuns. Já na classe Funcionario permaneceram apenas os atributos salário e carteira de trabalho, que são os necessários para contratar e pagar o funcionário da locadora, e na classe Cliente, foram colocados apenas o atributo dependentes, para indicar se mais alguém pode locar um filme no nome desse cliente. Se não tivéssemos criado a classe Pessoa, todos os atributos desta teriam que ser duplicados na classe Funcionario, e na Cliente, desnecessariamente. A classe que herda os atributos e métodos é chamada de filha ou subclasse, nesse caso, as classes Funcionario e Cliente são subclasses da Pessoa. Já a classe que é herdada, é chamada de mãe ou superclasse. Portanto, a classe Pessoa é uma superclasse.

Relembrando um pouco sobre modificadores de acesso, quando temos um atributo ou método declarado como private, somente a própria classe tem acesso a ele. Isso vale também para herança, as subclasses não herdam os atributos e métodos criados como private. Para que seja possível herdar, é necessário utilizar outros modificadores de acordo com a necessidade, podendo ser, por exemplo, um protected ou public. Já entendemos o porquê de utilizar a herança, mas como fazer isso no Java? Como dizer ao compilador que você está utilizando parte do código fonte de outra classe? Para isso existe uma palavra-chave chamada extends, que possibilita fazer uso da herança no Java. Veja no exemplo a seguir, como ficariam as três classes desenvolvidas no Java. public class Pessoa { private String nome; private String telefone; private String rg; private String cpf; private String estadoCivil; private String sexo; //implementação dos métodos } public class Cliente extends Pessoa{ private String dependentes; //implementação dos métodos } public class Funcionario extends Pessoa { private float salario; private String carteiraTrabalho; } 52

CURSOS TÉCNICOS SENAI

//implementação dos métodos

Observe que logo após o nome da classe, utilizamos a palavra reservada extends, seguida do nome da classe que queremos herdar. Fazendo isso, é como se copiássemos tudo que está dentro da classe Pessoa e colássemos dentro da classe Funcionario e Cliente, exceto os atributos e métodos declarados como private. Quando criamos um objeto do tipo Funcionario, por exemplo, não precisamos fazer nenhum tipo de referência à classe Pessoa para utilizar seus atributos e métodos. Veja no exemplo: public class Locadora{ public static void main(String[] args) { Funcionario funcionario = new Funcionario(); funcionario.setNome(“João”); funcionario.setRg(“89898789”); funcionario.setCpf(“021.234.543-90”); funcionario.setTelefone(“(47)30001122”); funcionario.setSexo(“Masculino”); funcionario.setEstadoCivil(“Casado”); funcionario.setCarteiraTrabalho(“9876234653”); funcionario.setSalario(2000); }

//implementação dos métodos

}

Observando o exemplo, nota-se que não há diferença nenhuma ao acessar os atributos que a classe Funcionario está herdando da Pessoa, é como se os atributos fossem exclusivamente da classe Funcionario. Pode acontecer de se herdar métodos com determinadas características, que não queremos utilizar em outras classes, e para refazer esse método, existe um mecanismo chamado de reescrita de métodos. Esse é o assunto da próxima seção de estudo.

PROGRAMAÇÃO ORIENTADA A OBJETOS I

53

SEÇÃO 2

Reescrita de Métodos Nem sempre os métodos herdados possuem o comportamento que queríamos. Nesses casos, é necessário reescrevê-los. Imagine que na classe Pessoa exista um método para cadastrar o cpf de uma pessoa, porém, esse método não faz nenhum tipo de validação para saber se o número informado é válido. Para fazer essa validação, é necessário reescrever o método de cadastro do cpf. Observe:

public class Pessoa { private String nome; private String telefone; private String rg; private String cpf; private String estadoCivil; private String sexo; public void cadastroCpf(String cpf){ this.cpf = cpf; } //implementação dos métodos } public class Funcionario extends Pessoa { private float salario; private String carteiraTrabalho; public void cadastroCpf(String cpf){ if(cpf.length() >= 11){ super.setCpf(cpf); } else{ System.out.println(“CPF inválido.”); } } }

//implementação dos métodos

Nesse exemplo, temos um método chamado cadastroCpf na classe Pessoa, onde ele apenas seta o valor do cpf informado no atributo da classe, sem fazer qualquer tipo de validação. Na classe Funcionario, reescrevemos o método de cadastro do cpf fazendo uma validação simples com relação ao tamanho do número informado. Tal documento, para ser válido, deve possuir pelo menos onze dígitos, logo, se informar menos, o cpf é inválido.

54

CURSOS TÉCNICOS SENAI

Agora, sempre que utilizarmos um objeto do tipo Funcionario para acessar o método cadastroCpf, ele invocará o método reescrito e não mais o da superclasse. O mesmo pode ser feito para a classe Cliente. Saiba que é possível que exista a necessidade de, em algum momento, chamar o método herdado ao invés do reescrito, basta, para isso, utilizar a palavra reservada super, que faz referência à superclasse, e acessará o método herdado. No exemplo anterior, foi utilizada a palavra super para acessar o método setCpf da superClasse. Atenção: A palavra super só pode ser utilizada dentro da subclasse.

Observe outro exemplo de uso do super.

public class Funcionario extends Pessoa { private float salario; private String carteiraTrabalho; public void cadastroCpf(String cpf){ if(cpf.length() >= 11){ super.cadastroCpf(cpf); } else{ System.out.println(“CPF inválido.”); } } }

//implementação dos métodos

Nesse exemplo, ao invés de chamar o método setCpf, foi chamado o método cadastroCpf, herdado da superclasse. É feita a validação no método reescrito, se estiver tudo certo, é chamado o método herdado para fazer o cadastro efetivo. A reescrita de métodos é muito importante para mudar o comportamento de um método, para se adequar as necessidades da classe que o está herdando.

DICA Agora, realize os exercícios 22 ao 26 do caderno de atividades práticas e teste o que acabou de aprender. Ah! Preste atenção na informação do exercício 25, há um comentário sobre duas expressões novas. Continue atento!

PROGRAMAÇÃO ORIENTADA A OBJETOS I

55

Unidade de estudo 7 Seções de estudo Seção 1 - Polimorfismo

Polimorfismo SEÇÃO 1

Polimorfismo Se entrar alguém na locadora e pedir para falar com alguma pessoa, esta pode ser tanto um cliente como um funcionário, certo? Afinal, cliente e funcionário são pessoas. Com base nessa ideia, se pode fazer a seguinte operação no nosso sistema: public class Locadora{ public static void main(String[] args) { Funcionario funcionario = new Funcionario(); funcionario.setNome(“João”); funcionario.setRg(“89898789”); funcionario.setCpf(“021.234.543-90”); funcionario.setTelefone(“(47)30001122”); funcionario.setSexo(“Masculino”); funcionario.setEstadoCivil(“Casado”); funcionario.setCarteiraTrabalho(“9876234653”); funcionario.setSalario(2000);

Pessoa pessoa = new Pessoa(); pessoa = funcionario;



}



//implementação dos métodos

}

A operação realizada só é possível graças ao polimorfismo, que é a capacidade de fazer referência a um objeto de formas diferentes.

No exemplo, estamos nos referenciando a um funcionário como sendo uma pessoa. Mas tome cuidado, um objeto pode fazer referência a outros objetos, porém, ele nunca muda de tipo. Se ele foi criado como sendo um objeto do tipo Funcionario, ele sempre vai ser assim, até que seja destruído.

Veja outro exemplo para entender melhor. Imagine que na classe Pessoa tenha um método chamado “queTipoSou”, que imprime uma frase mostrando de que tipo é um determinado objeto. Esse mesmo método é criado na classe Funcionario. Fazendo isso, temos as seguintes classes:

PROGRAMAÇÃO ORIENTADA A OBJETOS I

57

public class Pessoa { private String nome; private String telefone; private String rg; private String cpf; private String estadoCivil; private String sexo; public void queTipoSou(){ System.out.println(“Pessoa!”); } //implementação dos métodos } public class Funcionario extends Pessoa { private float salario; private String carteiraTrabalho; public void queTipoSou(){ System.out.println(“Funcionário!”); } }

//implementação dos métodos

Se criarmos um objeto do tipo Funcionario e um objeto do tipo Pessoa e atribuirmos o objeto Funcionario ao objeto Pessoa, e, após isso, chamarmos o método quetipoSou, que frase será impressa? “Funcionário!” ou “Pessoa!”? Antes de responder a essa pergunta, veja o exemplo:

public class Locadora{ public static void main(String[] args) { Funcionario funcionario = new Funcionario(); funcionario.setNome(“João”); funcionario.setRg(“89898789”); funcionario.setCpf(“021.234.543-90”); funcionario.setTelefone(“(47)30001122”); funcionario.setSexo(“Masculino”); funcionario.setEstadoCivil(“Casado”); funcionario.setCarteiraTrabalho(“9876234653”); funcionario.setSalario(2000);

Pessoa pessoa = new Pessoa(); pessoa = funcionario;



pessoa.queTipoSou();



}



//implementação dos métodos

}

58

CURSOS TÉCNICOS SENAI

Agora temos um objeto do tipo Pessoa, que faz referência a um objeto do tipo Funcionario. Lembre-se que um objeto sempre será do tipo que foi criado, nunca muda, até ser destruído. Logo, se utilizar o objeto do tipo Pessoa para chamar o método queTipoSou, a frase impressa será “Funcionário”, apesar de estar utilizando o objeto pessoa para chamar o método. Quem possibilita isso é o polimorfismo. O assunto da próxima unidade de estudos é agregação e composição. Continue atento e vá fazendo os exercícios do caderno de atividades!

PROGRAMAÇÃO ORIENTADA A OBJETOS I

59

Unidade de estudo 8 Seções de estudo Seção 1 - Agregação e composição

Agregação e Composição SEÇÃO 1

Agregação e Composição Assim como na herança, que uma classe estende de outra para utilizar seus atributos e métodos, a agregação e a composição também têm esse mesmo objetivo. Veja agora o que é agregação e composição, e qual a diferença entre esses conceitos com relação à herança. Os conceitos de agregação e composição, inicialmente, podem gerar alguma dúvida, mas, a forma de utilizar é exatamente a mesmo, o que muda é o momento em que cada um será utilizado. A agregação ou a composição devem ser utilizadas sempre que existir a necessidade de características de outro objeto, dentro de uma classe. Veja um exemplo, para entender melhor.

public class Pessoa { private String nome; private String telefone; private String rg; private String cpf; private String estadoCivil; private String sexo; private String endereco; private String bairro; private String cep; private String cidade; private String complemento; //implementação dos métodos }

Nesse exemplo, temos uma classe chamada Pessoa, alguns de seus atributos são correspondentes a um endereço, como endereço, bairro, cidade e cep. Nós poderíamos criar outra classe, chamada Endereco, e nesta colocar todos os atributos que estão na classe Pessoa e que se referem a um endereço. Com isso, criaremos uma nova classe, que representa um endereço, e que pode ser utilizada dentro da classe Pessoa, para isso, basta criar um atributo do tipo Endereco dentro da classe Pessoa. Veja.

PROGRAMAÇÃO ORIENTADA A OBJETOS I

61

public class Endereco { private String rua; private String bairro; private String cidade; private String cep; private String complemento; }

// implementação dos métodos

Agora, com a classe Endereco já criada, é possível retirar todos os atributos que representam um endereço e que estão dentro da classe Pessoa. Mas, uma pessoa precisa de um endereço, então, como fazer? Vamos utilizar a classe que acabamos de criar, chamada Endereco, e fazer uma agregação. A implementação fica desta forma:

public class Pessoa { private String nome; private String telefone; private String rg; private String cpf; private String estadoCivil; private String sexo; private Endereco endereco; public Endereco getEndereco() { return endereco; } public void setEndereco(Endereco endereco) { this.endereco = endereco; } }

//implementação dos demais métodos

Note que agora temos acesso aos atributos do endereço por meio do atributo declarado, dentro da classe Pessoa do tipo Endereco. Para ter acesso aos atributos, basta fazer o seguinte:

public class Locadora{ public static void main(String[] args) { Pessoa pessoa = new Pessoa(); pessoa.getEndereco().setBairro(“Bom Retiro”); pessoa.getEndereco().setCep(“89222-365”); //... } }

62

CURSOS TÉCNICOS SENAI

Observe que, anteriormente, o exemplo foi utilizado como uma agregação, mas será que esse exemplo não poderia ser considerado uma composição? Entenda melhor o conceito de cada um deles. Considera-se uma agregação quando todas as classes utilizadas na operação podem existir, sem depender umas das outras.

No exemplo, temos uma classe Pessoa e uma classe Endereco, nesse caso, uma pessoa existe sem um endereço e um endereço pode existir sem uma pessoa, logo, a utilização de um objeto Endereco dentro da classe Pessoa é denominado como agregação. Para representar uma agregação, podemos utilizar um diagrama que representa a relação entre as classes, onde um losango vazado (não preenchido) é utilizado no lado da classe que irá possuir a outra. Veja o exemplo:

Se o “contém” encaixar melhor na frase, você deve utilizar ou a agregação ou a composição. Exemplo: Um cliente é uma pessoa. Uma pessoa contém um endereço.

Figura 8: Exemplo de agregação

A composição é definida quando pelo menos uma das classes não tem sentido, quando utilizada separadamente da outra.

Um exemplo muito utilizado, para explicar esse conceito, é um pedido de compra. Esse pedido é uma classe e um item de compra é outra classe, porém, um item de compra não pode existir sem que exista um pedido de compra, ele é dependente do pedido. Por isso, temos a utilização de uma composição, a classe item de compra não tem sentido quando utilizada separadamente. Para ilustrar a composição, podemos utilizar um diagrama, assim como foi utilizado na agregação, porém, a diferença é que na composição o losango é preenchido. Veja:

Nos exemplos apresentados no destaque, você pôde notar facilmente na primeira frase que um cliente é uma pessoa e não contém uma pessoa, logo, se utiliza herança. Já na segunda frase, uma pessoa contém um endereço e não é um endereço, logo, , se utiliza a agregação. Em vários momentos do curso, você acompanhou a informação de que os conceitos podem permitir reaproveitamento de códigos já desenvolvidos em outras classes, tornando as aplicações cada vez mais fáceis de compreender e manutenir. O próximo assunto a ser estudado, está ligado a essa funcionalidade: as classes abstratas. Mas antes de continuar, realize os exercícios 28 e 29 do caderno de atividades práticas.

Figura 9: Exemplo de composição

Fazendo uso da composição e/ou da agregação, podemos centralizar características que serão utilizadas por várias outras classes, e que podem ou não ser utilizadas separadamente. Dessa forma, se pode facilitar possíveis manutenções do sistema e, é claro, praticar o reaproveitamento de código. E quanto ao fato de utilizar a herança, ao invés de agregação ou composição? Como saber quando utilizar um ou outro conceito? A herança é utilizada quando uma classe pode ser vista de duas formas, como no exemplo do cliente, que afirmamos que um cliente pode ser uma pessoa. No exemplo, que uma pessoa não pode ser, mas pode conter um endereço, utiliza-se a agregação ou composição. Para facilitar a identificação de qual conceito utilizar, existem dois exemplos muito utilizados e simples. Basta montar frases utilizando “é” ou “contém”. Se na frase encaixar o “é”, então você deve utilizar a herança.

PROGRAMAÇÃO ORIENTADA A OBJETOS I

63

Unidade de estudo 9 Seções de estudo Seção 1 - Classes abstratas

Classes Abstratas SEÇÃO 1

Classes abstratas As classes abstratas não podem ser utilizadas como instância direta, ou seja, você não pode utilizar o new para criar um objeto de uma classe abstrata. Mas para que serve uma classe, se você não pode instanciá-la? Podemos dizer que uma classe abstrata é utilizada como um “molde” para outras classes. Para fazer isso, vamos utilizar a herança. Vamos trabalhar novamente com as classes Pessoa, Funcionario e Cliente? No sistema de locadora, teremos que cadastrar os funcionários e os clientes da loja. Como funcionários e clientes são pessoas, faz sentido ter um cadastro de pessoas, mas ao cadastrar é preciso saber quem é funcionário e quem é cliente. Podemos, então, utilizar uma classe Pessoa para reunir todas as características em comum das demais classes, que podem ser consideradas pessoas. Fazendo isso, teremos uma classe modelo, que será a Pessoa, e outras classes que irão estender dessa modelo para reaproveitar suas características. Para definir uma classe como sendo um “modelo”, se utiliza a palavra chave abstract. Dentro dessa classe, podemos ou não, ter métodos abstratos, assim como, ter métodos não abstratos. Tornando a classe Pessoa abstrata, ela ficaria assim:

abstract class Pessoa { private String nome; private String telefone; private String rg; private String cpf; private String estadoCivil; private String sexo; abstract void cadastroCpf(String cpf); }

//implementação dos demais métodos

Agora temos a classe Pessoa como sendo abstrata, note que apenas adicionamos a palavra chave abstract no início da criação da classe. Além dessa alteração, criamos também um método abstrato, o método cadastroCpf, isso significa que na classe abstrata Pessoa existe apenas a assinatura do método, e este deverá ser implementado nas classes que estenderem da classe Pessoa. Logo, as classes Funcionario e Cliente ficam da seguinte forma:

PROGRAMAÇÃO ORIENTADA A OBJETOS I

65

public class Funcionario extends Pessoa { private float salario; private String carteiraTrabalho; public void cadastroCpf(String cpf){ if(cpf.length() >= 11){ super.cadastroCpf(cpf); } else{ System.out.println(“CPF do funcionário é inválido.”); } } //implementação dos demais métodos } public class Cliente extends Pessoa { private float dependentes; public void cadastroCpf(String cpf){ if(cpf.length() >= 11){ super.cadastroCpf(cpf); } else{ System.out.println(“CPF do cliente é inválido.”); } } }

//implementação dos demais métodos

Note que ambas as classes, utilizaram a palavra extends para trabalhar com herança, estendendo da classe Pessoa. Como na classe Pessoa existe um método abstrato, este deve ser implementado em todas as classes filhas da classe Pessoa, e isso foi feito nas duas classes filhas. Resumindo, quais são as principais características das classes abstratas?

▪▪ Elas servem como “modelo” para outras classes. ▪▪ Não podem ser instanciadas, ou seja, não se pode utilizar a palavra-

-chave new para uma classe abstrata.

▪▪ Pode-se implementar métodos abstratos dentro de uma classe abstrata. ▪▪ Métodos abstratos não possuem implementação, apenas a assinatura do método. ▪▪ Pode-se implementar métodos não abstratos dentro de uma classe abstrata. ▪▪ Os métodos abstratos devem ser implementados dentro das classes

filhas.

66

CURSOS TÉCNICOS SENAI

Pode-se ainda representar as classes com o uso de uma classe abstrata por meio dediagramas de classes UML. Veja na figura a seguir.

Figura 10: Representação da herança utilizando classe abstrata

Perceba que esse diagrama é aquele apresentado quando estudamos a herança. Sabe por quê? Porque as classes abstratas são utilizadas para se trabalhar com herança e como não podemos instanciar uma classe abstrata, ela é utilizada para ser herdada por outras classes. Para não se confundir, lembre sempre que a herança existe, perfeitamente, sem as classes abstratas, mas, as classes abstratas dependem da herança para serem utilizadas. Na próxima unidade de estudo você aprenderá a criar as interfaces. Continue atento e bom estudo!

PROGRAMAÇÃO ORIENTADA A OBJETOS I

67

Unidade de estudo 10 Seções de estudo Seção 1 - Interface

Interface SEÇÃO 1 Interface

A linguagem de programação Java não permite que classes herdem de mais de uma classe, ou seja, elas podem ter no máximo uma superclasse. Para suprir essa necessidade de herdar propriedades de mais de uma classe, foi desenvolvido o conceito de interfaces. Diferente das classes abstratas, as interfaces não podem conter implementações de métodos e declarações de atributos que não sejam do tipo public, static e final. As interfaces possuem apenas as assinaturas dos métodos, por isso dizemos que as elas são como contratos, depois que assinamos, temos a obrigação de implementar todos os métodos do contrato, ou seja, implementar todas as assinaturas de métodos que existem na interface. Para criar uma interface, basta substituir a palavra class por interface. Para ilustrar, vamos alterar a nossa classe Pessoa para que ela se torne uma interface, veja o exemplo a seguir:

interface Pessoa { String nome = “Maria”; }

public void cadastroCpf(String cpf); //assinatura dos demais métodos

Nesse exemplo, não temos mais a palavra class, e sim interface. Quando existir um atributo criado dentro de uma interface, ele já deve ser inicializado, pois, mesmo sem informar, esse atributo é final (constante), além de estático e público. Além dessas mudanças, os métodos não podem mais ser implementados. Observe que no exemplo, temos apenas a assinatura do método. Quando utilizamos uma interface em outra classe, dizemos que estamos implementando uma interface, para isso, utilizamos a palavra reservada implements. Observe o exemplo aplicado às classes Funcionario e Cliente.

PROGRAMAÇÃO ORIENTADA A OBJETOS I

69

public class Funcionario implements Pessoa { private float salario; private String carteiraTrabalho; public void cadastroCpf(String cpf){ if(cpf.length() >= 11){ super.cadastroCpf(cpf); } else{ System.out.println(“CPF do funcionário é inválido.”); } } //implementação dos demais métodos } public class Cliente implements Pessoa { private float dependentes; public void cadastroCpf(String cpf){ if(cpf.length() >= 11){ super.cadastroCpf(cpf); } else{ System.out.println(“CPF do cliente é inválido.”); } } }

//implementação dos demais métodos

Perceba que nas duas classes utilizamos a palavra-chave implements para afirmar que as classes Funcionario e Cliente vão implementar todos os métodos da interface Pessoa. Uma das vantagens em utilizar interface é que se pode implementar mais de uma na mesma classe. Para fazer isso, basta separar por vírgula as interfaces que se deseja implementar, exemplo:

public class Funcionario implements Pessoa, SegundaInterface, TerceiraInterface { //Criação de atributos //implementação dos métodos }

Nesse exemplo, separamos por vírgula três interfaces - Pessoa, SegundaInterface e TerceiraInterface, pois, estamos nos responsabilizando por assinar três contratos, e com isso, temos que implementar os métodos assinados em todas as interfaces.

70

CURSOS TÉCNICOS SENAI

Deve ficar bem claro que quando se fala em interface, é que, aqui, não é definido como as coisas são feitas (implementação), mas sim, o que será feito (assinatura). Na programação orientada a objeto, é muito importante pensar dessa forma, fazendo assim, as classes acabam ficando mais fáceis de entender e de manutenir.

Diversos autores aconselham amplamente o uso de interfaces, ao invés de herança. A herança, se utilizada sem conhecimento, pode tornar seu código perigoso. Já no uso de interfaces, cada classe é responsável pela sua implementação, pois estamos programando voltados à interface, o que é mais aconselhado.

DICA Na próxima unidade de estudos, você vai entender como o computador consegue executar várias coisas ao mesmo tempo, mas antes, teste o que aprendeu nesta unidade realizando os exercícios 33 e 34 do caderno de atividades práticas. Até mais!

PROGRAMAÇÃO ORIENTADA A OBJETOS I

71

Unidade de estudo 11 Seções de estudo Seção 1 - Apêndice – Programação concorrente e threads

Apêndice – Programação Concorrente e Threads Seção 1

Programação concorrente e threads Você já se perguntou como o computador consegue executar várias coisas ao mesmo tempo? Essa é uma grande vantagem que a máquina tem sobre os seres humanos. Ouvir música e utilizar um editor de texto para escrever sobre algo que você está pesquisando na internet... Como o computador consegue fazer isso ao mesmo tempo? O computador divide essas tarefas em processos, ou seja, cada ação executada por ele é um novo processo. Por serem executados todos ao mesmo tempo, dizemos que são processos paralelos. Até aqui tudo bem, cada atividade é um processo, mas imagine que o nosso sistema esteja sendo executado, então, torna-se um processo para o sistema operacional do computador. Agora, imagine que dentro do nosso sistema precisamos fazer mais de uma atividade por vez, como fazer isso? Precisamos enviar um email, ao mesmo tempo em que um cliente realiza um cadastro de usuário ou exibir a interface gráfica para que o usuário possa visualizar o sistema. Tudo isso está sendo feito em paralelo, então, como controlar isso tudo? Criar mais processos? Nesse caso não, existe outro conceito que são as threads. Se dentro de um processo, temos várias atividades, que devem ser executas em paralelo, será preciso criar threads para gerenciar tudo isso. No Java, existe mais de uma forma de se utilizar as threads, porém, aqui você vai aprender a forma considerada mais correta, que é implementando a interface Runnable. Essa interface implementa uma thread. Fazendo isso no Java, teremos a seguinte classe:

public class Sistema implements Runnable{ //implementação dos métodos }

A classe que chamamos de Sistema, implementa a interface Runnable, e ao implementar essa a classe precisa implementar o método run, que é responsável por dar início à execução da thread. Veja no exemplo a seguir, uma implementação desse método.

PROGRAMAÇÃO ORIENTADA A OBJETOS I

73

public class Sistema implements Runnable{ private String nome; //get e set para a variável nome public void run() { int i = 0; while(i
View more...

Comments

Copyright ©2017 KUPDF Inc.
SUPPORT KUPDF