Logo Passei Direto
Buscar

Programação III - Unicesumar

User badge image

Enviado por Tiago em

páginas com resultados encontrados.
páginas com resultados encontrados.
left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

Prévia do material em texto

PROGRAMAÇÃO III 
PROFESSORES
Dr. Edson Alves de Oliveira Junior
Me. Andre Abdala Noel
Me. Márcia Cristina Dadalto Pascutti 
Me. Rafael Alves Florindo
Esp. Janaina Aparecida de Freitas
Esp. Victor de Marqui Pedroso
EXPEDIENTE
C397 CENTRO UNIVERSITÁRIO DE MARINGÁ. 
Núcleo de Educação a Distância. NOEL, Andre Abdala; OLIVEIRA JR, 
Edson Alves de; FREITAS, Janaina Aparecida de; PASCUTTI, Márcia Cris-
tina Dadalto; FLORINDO, Rafael Alves; PEDROSO, Victor de Marqui.
Programação III. 
Andre Abdala Noel, Edson Alves de Oliveira Junior, Janaina Apa-
recida de Freitas, Márcia Cristina Dadalto Pascutti, Rafael Alves 
Florindo e Victor de Marqui Pedroso.
Maringá - PR.: UniCesumar, 2020. 
216 p.
“Graduação - EaD”. 
1. Programação 2. Software 3. Sistema. EaD. I. Título. 
FICHA CATALOGRÁFICA
NEAD - Núcleo de Educação a Distância
Av. Guedner, 1610, Bloco 4 Jd. Aclimação - Cep 87050-900 | Maringá - Paraná
www.unicesumar.edu.br | 0800 600 6360 
Coordenador(a) de Conteúdo 
Danillo Xavier Saes
Projeto Gráfico e Capa
Arthur Cantareli, Jhonny Coelho
e Thayla Guimarães
Editoração
Sabrina Maria Pereira de Novaes
Design Educacional
Rossana Costa Giani
Revisão Textual
Ariane Andrade Fabreti
Ilustração
Marta Sayuri Kakitani
Fotos
Shutterstock CDD - 22 ed. 005.1 
CIP - NBR 12899 - AACR/2
ISBN 978-85-459-1712-0
Impresso por: 
Bibliotecário: João Vivaldo de Souza CRB- 9-1679
Diretoria Executiva Chrystiano Mincoff, James Prestes, Tiago Stachon Diretoria de Design Educacional 
Débora Leite Diretoria de Graduação Kátia Coelho Diretoria de Permanência Leonardo Spaine Diretoria 
de Pós-graduação, Extensão e Formação Acadêmica Bruno Jorge Head de Produção de Conteúdos Celso 
Luiz Braga de Souza Filho Gerência de Produção de Conteúdo Diogo Ribeiro Garcia Gerência de Projetos 
Especiais Daniel Fuverki Hey Supervisão do Núcleo de Produção de Materiais Nádila Toledo Supervisão 
de Projetos Especiais Yasminn Zagonel
NEAD - NÚCLEO DE EDUCAÇÃO A DISTÂNCIA
Reitor Wilson de Matos Silva Vice-Reitor Wilson de Matos Silva Filho Pró-Reitor de Administração Wilson de 
Matos Silva Filho Pró-Reitor Executivo de EAD William Victor Kendrick de Matos Silva Pró-Reitor de Ensino de 
EAD Janes Fidélis Tomelin Presidente da Mantenedora Cláudio Ferdinandi 
DIREÇÃO UNICESUMAR
BOAS-VINDAS
Neste mundo globalizado e dinâmico, nós tra-
balhamos com princípios éticos e profissiona-
lismo, não somente para oferecer educação de 
qualidade, como, acima de tudo, gerar a con-
versão integral das pessoas ao conhecimento. 
Baseamo-nos em 4 pilares: intelectual, profis-
sional, emocional e espiritual.
Assim, iniciamos a Unicesumar em 1990, com 
dois cursos de graduação e 180 alunos. Hoje, 
temos mais de 100 mil estudantes espalhados 
em todo o Brasil, nos quatro campi presenciais 
(Maringá, Londrina, Curitiba e Ponta Grossa) e 
em mais de 500 polos de educação a distância 
espalhados por todos os estados do Brasil e, 
também, no exterior, com dezenasde cursos 
de graduação e pós-graduação. Por ano, pro-
duzimos e revisamos 500 livros e distribuímos 
mais de 500 mil exemplares. Somos reconhe-
cidos pelo MEC como uma instituição de exce-
lência, com IGC 4 por sete anos consecutivos 
e estamos entre os 10 maiores grupos educa-
cionais do Brasil.
A rapidez do mundo moderno exige dos edu-
cadores soluções inteligentes para as neces-
sidades de todos. Para continuar relevante, a 
instituição de educação precisa ter, pelo menos, 
três virtudes: inovação, coragem e compromis-
so com a qualidade. Por isso, desenvolvemos, 
para os cursos de Engenharia, metodologias ati-
vas, as quais visam reunir o melhor do ensino 
presencial e a distância.
Reitor 
Wilson de Matos Silva
Tudo isso para honrarmos a nossa mis-
são, que é promover a educação de qua-
lidade nas diferentes áreas do conheci-
mento, formando profissionais cidadãos 
que contribuam para o desenvolvimento 
de uma sociedade justa e solidária.
P R O F I S S I O N A LT R A J E T Ó R I A
Dr. Edson Alves de Oliveira Junior
Pós-Doutorando em Experimentação em Computação Forense na PUC-RS. Possui 
doutorado em Ciências de Computação e Matemática Computacional pelo Instituto 
de Ciências Matemáticas e de Computação da Universidade de São Paulo (ICMC-
-USP). Possui mestrado e graduação em Ciência da Computação pela Universidade 
Estadual de Maringá (UEM). Professor adjunto do Departamento de Informática 
(DIN) da Universidade Estadual de Maringá (UEM). Possui experiência na área de 
Ciência da Computação, com ênfase em Engenharia de Software, atuando, principal-
mente, nos seguintes temas: Processos de Software, Linha de Produto de Software, 
Avaliação de Arquitetura de Software e de Linhas de Produto, Linha de Processo 
de Software, Gerenciamento de Variabilidades, Métricas e Modelos de Software, 
Frameworks, Modelagem e Metamodelagem UML, Ambientes de Desenvolvimento 
e Tecnologias Java.
http://lattes.cnpq.br/8717980588591239.
Me. Márcia Cristina Dadalto Pascutti
Possui mestrado em Ciência da Computação pela Universidade Federal do Rio Gran-
de do Sul (2002) e graduação em Processamento de Dados pela Universidade Es-
tadual de Maringá (1989). Atualmente, é professora no Instituto Federal do Paraná 
- Campus Umuarama, e está cursando o doutorado na PUC-PR. Atua, principalmente, 
nos seguintes temas: arquitetura de computadores, engenharia de software, proces-
samento de imagens, reconhecimento de padrões, visão computacional.
http://lattes.cnpq.br/0297217008123332
Me. Andre Abdala Noel
Mestre em Ciência da Computação pela Universidade Estadual de Maringá, com 
ênfase em sistemas de computação e bacharel em Ciência da Computação pela 
Universidade Estadual de Maringá.
É professor e programador. Possui boa experiência em programação, aplicando, 
também, na docência superior, desde 2008. Autor do site Vida de Programador, 
mantém-se ativo na comunidade de desenvolvedores.
http://lattes.cnpq.br/9035823171388697
P R O F I S S I O N A LT R A J E T Ó R I A
Esp. Janaina Aparecida de Freitas
Possui graduação em Informática pela Universidade Estadual de Maringá (2010) e 
especialização em MBA em Teste de Software pela UNICEUMA (2012). Atualmente, 
cursa o Programa de Mestrado em Ciência da Computação na Universidade Estadual 
de Maringá (UEM) e é graduanda de Letras – Português/Inglês na Unicesumar. Atua 
como professora mediadora, professora conteudista em gravação de aulas ao vivo e 
gravação de aulas conceituais nos cursos do NEAD – Núcleo de Educação a Distância 
– da Unicesumar, para os cursos de graduação de Sistemas para Internet, Análise 
e Desenvolvimento de Sistemas, Gestão da Tecnologia da Informação e Engenharia 
de Software, nas disciplinas de Engenharia de Software, Design Gráfico, Tópicos 
Especiais, Gerenciamento de Software, Design de Interação Humano-Computador, 
Projeto Implementação e Teste de Software. Além disso, tem experiência em inicia-
tiva privada na área de Análise de Sistemas e Testes de Software.
http://lattes.cnpq.br/4906244382612830
Esp. Victor de Marqui Pedroso
Possui Pós-Graduação em Banco de dados Oracle e DB2 pelo Centro Universitário 
de Maringá (2009) e graduação em Tecnologia em Processamento de Dados pelo 
Centro Universitário de Maringá (2003). Tem experiência como analista de sistemas, 
documentador, homologador e programador de software. Possui experiência em 
desenvolvimento utilizando a ferramenta Delphi. Já trabalhou como Professor Me-
diador e, atualmente, trabalha como Professor Formador dos cursos de Análise e 
Desenvolvimento de Sistemas e Sistemas para Internet, ministrando as disciplinas 
de Banco de Dados e Design de Interação.
http://lattes.cnpq.br/8611697826182780
Me. Rafael Alves Florindo
Mestrado em Gestão do Conhecimento nas Organizações na linha de pesquisa Edu-
cação e Conhecimento pela PPGGCO – Unicesumar – Centro Universitário de Maringá 
(2017). É especialista em Desenvolvimento de Sistema para Web pela UEM – Universi-
dade Estadual de Maringá (2008). Graduado em Ciênciada Computação pela FAI – Fa-
culdades Adamantinenses Integrada. Pós-graduando em Docência no Ensino Superior: 
Tecnologias Educacionais e Inovação e Banco de Dados pela Unicesumar. Professor 
– Ensino Técnico pela SEED-PR desde 2009. Professor autor, formador e mediador do 
EAD - Ensino a Distância da Unicesumar desde 2014, nos Cursos de TI: Sistemas para 
Internet, Análise e Desenvolvimento de Sistemas, Gestão da Tecnologia da Informação 
e Engenharia de Software. Professor presencial da Faculdade Unifamma desde 2019, 
no curso de Engenharia de Software e Sistema de Informação.
http://lattes.cnpq.br/7246554526271622
D A D I S C I P L I N AA P R E S E N TA Ç Ã O
PROGRAMAÇÃO III
Seja bem-vindo(a)!
Prezado(a) acadêmico(a), é com muito prazer que lhe apresentamos o livro de Programação III.
Este livro está organizado em cinco unidades e todas estão, estreitamente, relacionadas. Na 
Unidade 1, apresentaremos alguns conceitos referentes à disciplina. Você notará, durante a 
leitura das outras unidades, que esses conceitos são utilizados com frequência.
A engenharia de software surgiu mediante a necessidade de tornar o desenvolvimento de 
software confiável, com etapas bem definidas, custo e cronograma previsíveis, fatos que não 
aconteciam até 1968, quando o termo engenharia de software foi proposto. Além disso, gosta-
ríamos de ressaltar que o software compreende, além dos programas, toda a documentação 
referente a ele, e a engenharia de software é a disciplina que trata dessa documentação.
Na Unidade 2, daremos início à aplicação dos conhecimentos da engenharia de software na 
linguagem de programação Java. Abordaremos, primeiramente, os conceitos relacionados 
a modificadores de acesso e a encapsulamento. Esses recursos formam um dos pilares da 
programação orientada a objetos, recurso este que garante a integridade e o controle de 
acesso aos atributos e métodos.
Continuando a aplicação dos conceitos de engenharia de software, na Unidade 3, abarcaremos 
mais dois pilares da programação orientada a objetos: a herança e o polimorfismo. Ambos 
estão relacionados, uma vez que, a partir do recurso da herança, ou seja, quando o filho herda 
A P R E S E N TA Ç Ã O D A D I S C I P L I N A
características do pai, é possível especializar alguma operação. Nesse caso, temos que o filho 
pode implementar uma ação que o pai desenvolve, contudo ela pode ser diferente ou igual.
Na Unidade 4, abordaremos algumas regras de desenvolvimento. A primeira será as classes 
abstratas, que funcionarão como modelo de desenvolvimento para outras classes que estão 
recebendo herança dela, ou seja, a classe que herda de uma classe abstrata deve implementar 
os métodos que estão marcados para serem implementados nas classes filhas. Outra regra é 
a interface, esta rege um contrato entre analista e desenvolvedor; aqui, quando construímos 
uma interface e uma classe a implementa, ela é obrigada a implementar todos os métodos, 
funcionando, assim, como um contrato.
Finalmente, chegamos à última unidade do nosso material. Esta unidade é o fechamento 
das etapas do processo de software, onde realizaremos a implementação de um estudo de 
caso por meio da realização da nova análise desse estudo, agora, na visão do desenvolvedor.
Assim, chegamos ao final do nosso livro. Esperamos, sinceramente, que a sua leitura 
seja agradável e que este conteúdo possa contribuir para o seu crescimento pessoal, 
acadêmico e profissional.
ÍCONES
Sabe aquela palavra ou aquele termo que você não conhece? Este ele-
mento ajudará você a conceituá-la(o) melhor da maneira mais simples.
conceituando
No fim da unidade, o tema em estudo aparecerá de forma resumida 
para ajudar você a fixar e a memorizar melhor os conceitos aprendidos. 
quadro-resumo
Neste elemento, você fará uma pausa para conhecer um pouco 
mais sobre o assunto em estudo e aprenderá novos conceitos. 
explorando Ideias
Ao longo do livro, você será convidado(a) a refletir, questionar e 
transformar. Aproveite este momento! 
pensando juntos
Enquanto estuda, você encontrará conteúdos relevantes 
online e aprenderá de maneira interativa usando a tecno-
logia a seu favor. 
conecte-se
Quando identificar o ícone de QR-CODE, utilize o aplicativo Unicesumar 
Experience para ter acesso aos conteúdos online. O download do aplicativo 
está disponível nas plataformas: Google Play App Store
CONTEÚDO
PROGRAMÁTICO
UNIDADE 01 UNIDADE 02
UNIDADE 03
UNIDADE 05
UNIDADE 04
FECHAMENTO
MODELAGEM DE 
SISTEMAS
10
MODIFICADORES JAVA 
E ENCAPSULAMENTO
45
78
HERANÇA E 
POLIMORFISMO
115
CLASSES ABSTRATAS 
E INTERFACES
150
ESTUDO DE CASO: 
ANÁLISE CLÍNICA
202
CONCLUSÃO GERAL
1
MODELAGEM DE
SISTEMAS
PLANO DE ESTUDO 
A seguir, apresentam-se as aulas que você estudará nesta unidade: • Modelagem de sistemas • Ferra-
mentas CASE (Computer-Aided Software Engineering) • Introdução à UML (Unified Modeling Langua-
ge) • Conceitos básicos de orientação a objetos • Diagrama de classes.
OBJETIVOS DE APRENDIZAGEM 
• Expor a importância da modelagem de sistemas • Entender as Ferramentas CASE (Computer-Aided 
Software Engineering) • Entender a UML (Unified Modeling Language ou Linguagem de Modelagem 
Unificada) • Apresentar os conceitos básicos de orientação a objetos • Entender a estrutura do sistema 
por meio de elementos, tais como classes, atributos e associações entre os objetos.
PROFESSORES 
Dr. Edson Alves de Oliveira Junior
Me. Andre Abdala Noel
Me. Márcia Cristina Dadalto Pascutti 
Me. Rafael Alves Florindo 
Esp. Janaina Aparecida de Freitas
Esp. Victor de Marqui Pedroso
INTRODUÇÃO
Caro(a) aluno(a), nesta primeira unidade, você verá uma revisão dos 
conceitos de modelagem de sistema. Este é o processo de elaboração de 
modelos abstratos de um sistema, normalmente, representado por meio 
de um diagrama, em que cada um desses modelos apresenta uma visão 
ou uma perspectiva diferente do sistema (SOMMERVILLE, 2011). Esses 
modelos, normalmente, são elaborados utilizando uma notação gráfica, 
que, em nosso caso, será a UML(Unified Modeling Language ou Lingua-
gem de Modelagem Unificada).
A UML define, em sua versão atual, 21 tipos de diagramas para o uso 
na modelagem de software. Nesta unidade, veremos, somente, o diagrama 
de classe. Se você quiser conhecer os outros, consulte alguns livros relacio-
nados nas referências. Como nosso objetivo, aqui, é mostrar a modelagem 
de um sistema, utilizaremos, somente, esse diagrama.
Primeiramente, exporemos a importância de realizar a modelagem de 
um sistema de software. Esta se baseia na utilização de notações gráficas 
e textuais com o objetivo de construir modelos que representem as partes 
essenciais de um sistema. Depois, passaremos a entender as Ferramentas 
CASE (Computer-aided Software Engineering) e UML (Unified Modeling 
Language ou Linguagem de Modelagem Unificada). Todos os artefatos de 
software produzidos durante a modelagem serão usados como base para 
as fases seguintes do ciclo de desenvolvimento de sistemas, como as fases 
de projeto e de implementação. 
Em seguida, apresentaremos a você os conceitos básicos de Orientação a 
Objetos (OO) para entender, por meio de elementos, a estrutura do sistema. 
Por último, mostraremos o diagrama de classes. Este é o mais importante 
e, também, o mais utilizado da UML, além de servir de apoio para a maioria 
dos diagramas. O diagrama de classes define a estrutura das classes identi-
ficadas para o sistema, mostrando os atributos e os métodos de cada uma, 
além de estabelecer como elas se relacionam e trocam informações entre si. 
U
N
ID
A
D
E
 1
12
1 
MODELAGEM DE 
SISTEMAS
Caro(a) aluno(a), a necessidade de planejamento no desenvolvimento de sistemas 
de informação leva ao conceito de modelagem de software, ou seja, antes de o 
software ser concebido, deve-se criar um modelo para ele. Um modelo pode ser 
entendido como uma representação idealizada de um sistema a ser construído. 
São exemplos: maquetesde edifício, plantas de casa, fluxogramas etc.
A modelagem de sistemas de software se baseia na utilização de notações gráficas 
e textuais com o objetivo de construir modelos que representem as partes essenciais 
de um sistema. São várias as razões para utilizar modelos na construção de sistemas:
1. No desenvolvimento do software, usamos desenhos gráficos denomina-
dos diagramas, a fim de representar o comportamento do sistema. Esses 
diagramas seguem um padrão lógico e possuem uma série de elementos 
gráficos que carregam um significado pré-definido.
2. Apesar de um diagrama expressar diversas informações de forma gráfica, 
em diversos momentos, há a necessidade de adicionar informações em 
forma de texto, com o objetivo de explicar ou definir certas partes. A 
modelagem de um sistema em forma de diagrama, em conjunto com a 
informação textual, forma a documentação de um sistema de software.
3. O rápido crescimento da capacidade computacional das máquinas re-
sultou na demanda de sistemas de software cada vez mais complexos, 
que tirassem proveito de tal capacidade. Por sua vez, o surgimento desses 
U
N
IC
E
S
U
M
A
R
13
sistemas gerou a necessidade de reavaliação no desenvolvimento de siste-
mas. Desde o aparecimento do primeiro computador até os dias de hoje, 
as técnicas para a construção de sistemas computacionais têm evoluído 
para suprir as necessidades do desenvolvimento de software. A seguir, a 
Figura 1 ilustra um parâmetro histórico da evolução digital:
O processo de desenvolvimento de software é uma atividade bastante complexa. 
Isto se reflete no alto número de projetos de software que não chegam ao fim ou que 
Os sistemas de software eram bastante simples e, 
dessa forma, as técnicas de modelagem também. Era 
a época dos fluxogramas e diagramas de módulos.
Nesta época, houve a expansão do mercado 
computacional. Sistemas complexos começavam 
a surgir e, por consequência, modelos mais 
robustos foram propostos. Além disso, surge a 
programação estruturada e, no final da década, a 
análise e o projeto estruturado.
Surge a necessidade de interfaces 
homem-máquina mais sofisticadas, o que 
originou a produção de sistemas de software 
mais complexos. A análise estruturada se conso-
lidou na primeira metade da década, e, em 1989, 
Edward Yourdon lançou o livro Análise Estrutura-
da Moderna, tornando-se referência no assunto.
Inicia-se um novo paradigma de modelagem, a 
análise orientada a objetos, como resposta para 
as dificuldades encontradas na aplicação da 
análise estruturada em certos domínios de 
aplicação.
O paradigma da orientação a objetos atinge a sua 
maturidade. Os conceitos de padrões de projetos 
(design patterns), frameworks de desenvolvimen-
to, componentes e padrões de qualidade 
começam a ganhar espaço. Surge, também, a 
Linguagem de Modelagem Unificada (UML), que 
é a ferramenta de modelagem utilizada no 
desenvolvimento atual de sistemas.
1950/60
Era a época dos fluxogramas e 
diagramas de módulos
1970
Expansão do mercado 
tecnológico
1980
Sistema da interface de 
usuário
1990
Novo paradigma de 
modelagem de sistemas de 
software
1990 e atualidade
Maturidade Digital
Figura 1 - Parâmetros históricos da evolução dos modelos na construção de sistemas.
Fonte: os autores.
U
N
ID
A
D
E
 1
14
Modelagem de sistema é o processo de desenvolvimento de modelos abstratos de um 
sistema, em que cada modelo apresenta uma visão ou perspectiva diferente desse. A 
modelagem, geralmente, representa o sistema com algum tipo de notação gráfica que, 
atualmente, quase sempre, é baseada em notações de UML (linguagem de modelagem 
unificada, do inglês Unified Modeling Language). Os modelos são usados durante o pro-
cesso de engenharia de requisitos para ajudar a extrair os requisitos do sistema; duran-
te o processo de projeto, são usados para descrever o sistema aos engenheiros que o 
implementam; e, após isso, são usados para documentar a estrutura e a operação do 
sistema. Um modelo é uma abstração do sistema a ser estudado, e não uma representa-
ção alternativa dele. Idealmente, uma representação deve manter todas as informações 
sobre a entidade representada. Uma abstração, deliberadamente, simplifica e seleciona 
as características mais salientes.
Fonte: adaptado de Sommerville (2011, p. 96).
explorando Ideias
extrapolam recursos de tempo e de dinheiro alocados. Em um estudo clássico sobre 
projetos de desenvolvimento de software, realizado em 1994, constatou-se que:
 ■ Porcentagem de projetos que terminam dentro do prazo estimado: 10%.
 ■ Porcentagem de projetos que são descontinuados antes de chegarem 
ao fim: 25%.
 ■ Porcentagem de projetos acima do custo esperado: 60%.
 ■ Atraso médio nos projetos: um ano.
Os modelos construídos na fase de análise devem ser, cuidadosamente, validados e 
verificados. O objetivo da validação é o de assegurar que as necessidades do cliente es-
tão sendo atendidas. Nessa atividade, os analistas apresentam os modelos criados para 
representar o sistema aos futuros usuários a fim de que esses modelos sejam validados.
Já a verificação objetiva analisar se os modelos construídos estão em conformi-
dade com os requisitos definidos. Na verificação dos modelos, é analisada a exatidão 
de cada um, separadamente, bem como a consistência entre eles. A verificação é uma 
etapa típica da fase de projeto e é a próxima etapa do desenvolvimento de software.
Caro(a) aluno(a), utilizaremos a UML para realizar a modelagem de sistemas. 
Nesse primeiro tópico, estudamos alguns conceitos relacionados à orientação 
de objetos e fizemos uma introdução à linguagem UML. Lembre-se de que os 
artefatos de software produzidos durante a modelagem servirão de base para a 
fase seguinte do ciclo de desenvolvimento de sistemas, ou seja, a fase de projeto.
U
N
IC
E
S
U
M
A
R
15
2 
FERRAMENTAS 
CASE 
(Computer-Aided
Software Engineering)
Uma ferramenta CASE é um software que pode ser utilizado para apoiar as ati-
vidades do processo de software, como a engenharia de requisitos, o projeto, o 
desenvolvimento de programa e os testes. As ferramentas CASE podem incluir 
editores de projeto, dicionários de dados, compiladores, depuradores, ferramentas 
de construção de sistemas, entre outros (SOMMERVILLE, 2011).
Sommerville (2011) expõe alguns exemplos de atividades que podem ser 
automatizadas utilizando a CASE. Dentre elas, estão:
1. O desenvolvimento de modelos gráficos de sistemas enquanto parte das 
especificações de requisitos ou do projeto de software.
2. A compreensão de um projeto utilizando um dicionário de dados que 
carrega informações sobre as entidades e a sua relação em um projeto.
3. A geração de interfaces com usuários a partir de uma descrição gráfica 
da interface, que é criada interativamente pelo usuário.
4. A depuração de programas pelo fornecimento de informações sobre um 
programa em execução.
5. A tradução automatizada de programas a partir da antiga versão de uma 
linguagem de programação, como a Cobol, para uma versão mais recente.
A tecnologia CASE está, atualmente, disponível para a maioria das atividades de 
rotina no processo de software, proporcionando, assim, algumas melhorias na 
qualidade e na produtividade de software.
U
N
ID
A
D
E
 1
16
Existem, basicamente, duas formas de classificação geral para as ferramentas 
CASE. A primeira delas divide-se em: Upper CASE, Lower CASE, Integrated-
-CASE e Best in Class:
 ■ Upper CASE ou U-CASE ou Front-End: são as ferramentas voltadas 
para as primeiras fases do processo de desenvolvimento de sistemas, 
como a análise de requisitos, o projeto lógico e a documentação. São uti-
lizadas por analistas e pessoas mais interessadas na solução do problema 
do que na implementação.
 ■ Lower CASE ou L-CASE ou Back-End: são, praticamente, o oposto das 
ferramentas Upper CASE. Elas oferecem suporte nas últimas fases do 
desenvolvimento, como a codificação, os testes e a manutenção.■ Integrated CASE ou I-CASE: são ferramentas que, além de englobarem 
características das Upper e Lower CASEs, oferecem, ainda, outras carac-
terísticas, como controle de versão, por exemplo. Entretanto são utiliza-
das somente em projetos de desenvolvimento muito extensos, por serem 
bastante caras e difíceis de operar.
 ■ Best in Class ou Kit de Ferramenta: semelhante às I-CASEs, os Kits de Fer-
ramenta, também, acompanham todo o ciclo de desenvolvimento. Entretanto 
possuem a propriedade de conjugar a sua capacidade a outras ferramentas 
externas complementares, as quais variam de acordo com as necessidades do 
usuário. Para melhor entendimento, podemos compará-las a um computador 
sem o kit multimídia: as Best in Class seriam o computador que funciona nor-
malmente, enquanto as outras ferramentas fariam o papel do kit multimídia, 
promovendo mais potencial de trabalho para a máquina. São mais usadas 
para o desenvolvimento corporativo, apresentando controle de acesso, versão 
e repositórios de dados, entre outras características.
A segunda forma divide as ferramentas CASE em orientadas à função e em orien-
tadas à atividade:
 ■ Orientadas à função: seriam as Upper CASE e Lower CASE. Baseiam-
-se na funcionalidade das ferramentas, ou seja, são as que têm funções 
diferentes no ciclo de vida de um projeto. Por exemplo, a representação, 
apenas, do Diagrama de Entidades e Relacionamentos (DER) ou do Dia-
grama de Fluxo de Dados (DFD).
 ■ Orientadas à atividade: seriam as Best in Class e as I-CASE, as quais pro-
cessam atividades, tais como especificações, modelagem e implementação.
U
N
IC
E
S
U
M
A
R
17
Além dos ambientes completos de engenharia de software, ferramentas de solução pon-
tual que resolvem tudo, desde reunião de requisitos até refatoração de projeto/código e 
teste, continuarão a evoluir e se tornarão mais capazes em funcionalidade. 
(Roger Pressman e Bruce Maxim)
pensando juntos
3 
INTRODUÇÃO 
À UML
(Unified Modeling
Language)
Segundo Booch, Rumbaugh e Jacobson (2006, p. 13), “a UML (Unified Modeling 
Language ou Linguagem de Modelagem Unificada) é uma linguagem-padrão 
para a elaboração da estrutura de projetos de software”, podendo ser utilizada 
para visualização, especificação, construção e documentação de artefatos de soft-
ware, por meio do paradigma de orientação a objetos. Além disso, a UML é a 
linguagem-padrão de modelagem de software adotada, internacionalmente, pela 
indústria de engenharia de software (GUEDES, 2007).
A UML não é uma linguagem de programação, mas uma linguagem de modelagem 
cuja meta é auxiliar os engenheiros de software a definirem as características do softwa-
re, tais como: os seus requisitos, o seu comportamento, a sua estrutura lógica, a dinâmica 
de seus processos e, até mesmo, as suas necessidades físicas em relação ao equipamento 
em que o sistema deverá ser implantado. Todas essas características são definidas por 
meio da UML antes do início do desenvolvimento do software (GUEDES, 2007).
U
N
ID
A
D
E
 1
18
De acordo com Booch, Rumbaugh e Jacobson (2006), a UML é apenas uma 
linguagem de modelagem e, também, é independente de processo de software, 
visto que pode ser utilizada em modelo cascata, em desenvolvimento evolucioná-
rio ou em qualquer outro processo utilizado para o desenvolvimento do software.
A notação UML utiliza diversos símbolos gráficos, existindo uma se-
mântica bem definida para cada um deles, o que permite elaborar diversos 
modelos. Além disso, a UML tem sido empregada, de maneira efetiva, em 
sistemas cujos domínios abrangem os sistemas de informações corporativos, 
os serviços bancários e os financeiros, os transportes, os serviços distribuídos 
baseados na web, entre outros. No entanto ela não se limita à modelagem de 
software, pois pode modelar sistemas, tais como o fluxo de trabalho no sis-
tema legal, a estrutura e o comportamento de sistemas de saúde e o projeto 
de hardware (BOOCH; RUMBAUGH; JACOBSON, 2006).
Ferramentas Case baseadas na Linguagem UML
Nesta unidade, já constatamos que as ferramentas CASE (Computer-Aided Soft-
ware Engineering – Engenharia de Software Auxiliada por Computador, em por-
tuguês) são softwares que, de alguma forma, colaboram na realização de uma ou 
mais atividades realizadas durante o processo de desenvolvimento de software. 
Agora, veremos alguns exemplos de ferramentas CASE que suportam a UML, a 
qual é, em geral, a sua principal característica. Existem várias delas no mercado, 
dentre as quais podemos destacar:
 ■ Rational Rose: esta ferramenta foi desenvolvida pela Rational Software 
Corporation, empresa que estimulou a criação da UML, sendo a primeira 
ferramenta CASE baseada nessa linguagem. Atualmente, a Rational Rose 
é bastante usada pelas empresas desenvolvedoras de software. Ela permite 
a modelagem dos diversos diagramas da UML e a construção de modelos 
de dados com a possibilidade de exportação para a construção da base 
de dados ou a realização de engenharia reversa de uma base de dados 
existente. Em 20 de fevereiro de 2003, a empresa Rational foi adquirida 
pela IBM, e a ferramenta foi renomeada como IBM Rational Architect. 
U
N
IC
E
S
U
M
A
R
19
 ■ Astah Professional: é uma ferramenta para a criação de diagramas UML 
e possui uma versão gratuita, o Astah Community, bem como outras ver-
sões pagas. A versão gratuita possui algumas restrições de funções, porém, 
para as que necessitaremos nesta unidade, ela será suficiente. Portanto, 
será essa a ferramenta que utilizaremos para modelar os diagramas da 
UML que aprenderemos. Anteriormente, ela era conhecida como Jude.
 ■ Visual Paradigm for UML ou VP-UML: esta ferramenta oferece uma 
versão que pode ser baixada gratuitamente, a Community Edition, porém 
ela não suporta todos os serviços e opções disponíveis nas versões stan-
dard ou professionais da ferramenta. Para quem deseja praticar a UML, 
a versão gratuita é uma boa alternativa, apresentando um ambiente ami-
gável e de fácil compreensão. 
 ■ Enterprise Architect: esta ferramenta não possui edição gratui-
ta como as anteriores, mas é uma das que mais oferecem recursos 
compatíveis com a UML 2.
O importante, em nossos estudos, é que você consiga entender como se inicia a 
modelagem do seu sistema. Para tanto, queremos que a informação não fique, 
apenas, anotada em um documento, mas que você facilite o processo de desen-
volvimento utilizando os recursos de modelagem e de construção de diagramas.
U
N
ID
A
D
E
 1
20
A UML é, totalmente, baseada no paradigma de Orientação a Objetos (OO). 
Sendo assim, para compreendê-la corretamente, precisamos, antes, estudar alguns 
dos conceitos relacionados à orientação a objetos.
Objetos
Segundo Melo (2004), um objeto é qualquer coisa, em forma concreta ou abstrata, 
que exista física ou apenas conceitualmente no mundo real. São exemplos de ob-
jetos: cliente, professor, carteira, caneta, carro, disciplina, curso, caixa de diálogo. 
Além disso, eles possuem características e comportamentos.
Classes
Uma classe é uma abstração de um conjunto de objetos que possuem os mesmos 
tipos de características e comportamentos, sendo representada por um retân-
gulo que possui três divisões. A primeira divisão armazena o nome da classe; a 
segunda, os atributos (características); enquanto a terceira carrega os métodos.
Geralmente, uma classe possui atributos e métodos, mas é possível encontrar 
aquelas com apenas uma dessas características ou, até mesmo, nenhuma, quando 
se trata de classes abstratas. A Figura 2 apresenta um exemplo de classe:
4 
CONCEITOS BÁSICOS 
DE ORIENTAÇÃO 
a Objetos
U
N
IC
E
S
U
M
A
R
21
De acordo com Melo (2004), o momento inicial para 
a identificação de classes, em um documento de re-
quisitos, é assinalar os substantivos. Note que esses 
substantivos podem levar a objetos físicos (cliente, 
livro, computador) ou a objetos conceituais (reserva, 
cronograma, norma).Em seguida, é preciso identifi-
car, somente, aqueles que possuem importância para 
o sistema, verificando o que, realmente, consiste em objeto e o que consiste em 
atributo. Ainda, é preciso fazer nova análise dos requisitos para identificar as classes 
implícitas no contexto trabalhado, excluir classes parecidas ou juntar duas classes 
em uma. Vale a pena ressaltar que esse processo será iterativo, sem a possibilidade 
de definir todas as classes de uma só vez.
Atributos
Uma classe, normalmente, possui atributos que representam as suas característi-
cas, as quais costumam variar de um objeto a outro, como o nome de um objeto 
da classe cliente ou a cor em um objeto da classe carro, por exemplo. Tais aspectos 
são os responsáveis por diferenciar um objeto de outro da mesma classe.
De acordo com Guedes (2007), na segunda divisão da classe, aparecem os 
atributos. Cada atributo deve possuir um nome e, eventualmente, o tipo de dado 
que armazena, por exemplo, integer, float ou char. Assim, a classe especifica a 
estrutura de um objeto sem informar quais serão os seus valores. Em relação ao 
objeto, esse corresponde à instância de uma classe, em determinado momento. 
Apresentaremos um exemplo para facilitar o seu entendimento:
Uma classe pessoa possui os atributos: nome, sexo e data de nascimento. Essa 
classe pode ter um objeto ou uma instância com 
os seguintes valores para cada atributo, respec-
tivamente: Márcia, feminino, 22/03/1969. Dessa 
forma, em um sistema, devemos trabalhar com 
as instâncias (objetos) de uma classe, pois os va-
lores de cada atributo são carregados nas ins-
tâncias (MELO, 2004). A figura, a seguir, mostra 
um exemplo de classe com atributos:
Cliente
Figura 2 - Exemplo de classe.
Fonte: os autores.
Figura 3 - Exemplo de classe com 
atributos / Fonte: os autores.
Pessoa
- nome : string
- sexo : string
- data_nascimento : date
+ operation1() : void
U
N
ID
A
D
E
 1
22
Métodos
Métodos são processos ou serviços realizados por uma classe e disponibilizados 
para o uso de outras classes em um sistema. Além disso, devem ficar armazenados 
na terceira divisão da classe. Os métodos são as atividades que a instância de uma 
classe pode executar (GUEDES, 2007).
Um método pode ou não receber parâmetros (valores que são utilizados du-
rante a execução do método) bem como retornar 
valores os quais podem representar o resultado da 
operação executada ou somente indicar se o pro-
cesso foi concluído com sucesso. Assim, um méto-
do representa um conjunto de instruções que são 
executadas quando o método é chamado. Um ob-
jeto da classe cliente, por exemplo, pode executar a 
atividade de incluir novo cliente. A Figura 4 apre-
senta um exemplo de uma classe com métodos:
Visibilidade
De acordo com Guedes (2007), a visibilidade é um símbolo que antecede um 
atributo ou um método e é utilizada para indicar o seu nível de acessibilidade. 
Existem, basicamente, três modos de visibilidade: o público, o protegido e o pri-
vado. Saiba mais sobre cada um nos tópicos a seguir, na Figura 5:
Figura 5 - Modos de visibilidade / Fonte: os autores.
Cliente
- nome : string
- endereço : string
- cidade : string
- UF : char
- CEP : char
+ incluirNovoCliente() : void
+ atualizarCliente() : void
Figura 4 - Exemplo de classe com 
métodos / Fonte: os autores.
O símbolo mais (+) 
indica visibilidade 
pública, ou seja, 
significa que o 
atributo ou o 
método pode ser 
utilizado por objetos 
de qualquer classe.
O símbolo sustenido 
(#) indica que a 
visibilidade é 
protegida, ou seja, 
determina que apenas 
objetos da classe 
possuidora do atributo 
ou do método ou de 
suas subclasses 
podem acessá-lo.
O símbolo menos (-) 
indica que a 
visibilidade é 
privada, ou seja, 
somente os objetos 
da classe possuidora 
do atributo ou do 
método poderão 
utilizá-lo.
(+) (#) (-)
U
N
IC
E
S
U
M
A
R
23
Note que, no exemplo da classe cliente, tanto os atributos quanto os 
métodos apresentam a sua visibilidade representada à esquerda de seus 
nomes. Assim, os atributos nome, sexo e data_nascimento possuem visi-
bilidade privada, pois apresentam o símbolo de menos (-) à esquerda da 
sua descrição. Já os métodos IncluirNovoCliente() e AtualizarCliente() 
apresentam visibilidade pública, assim como indica o símbolo +, acres-
centado à esquerda de sua descrição.
Herança (generalização/especialização)
A herança permite que as classes de um sistema compartilhem atributos e mé-
todos, otimizando, assim, o tempo de desenvolvimento com a diminuição de 
linhas de código, o que facilita futuras manutenções (GUEDES, 2007). A herança 
(ou generalização/especialização) acontece entre classes gerais (chamadas de 
superclasses ou classes-mãe) e classes específicas (chamadas de subclasses ou 
classes-filha) (BOOCH; RUMBAUGH; JACOBSON, 2006).
A herança significa que os objetos da subclasse podem ser utilizados em 
qualquer local em que a superclasse ocorra, e não vice-versa. A subclasse herda 
as propriedades da mãe, ou seja, os seus atributos e métodos, bem como pode 
possuir atributos e métodos próprios, além dos herdados.
De acordo com Guedes (2007), a vantagem do uso da herança é que, 
quando uma classe é declarada com os seus atributos e métodos especí-
ficos e, após isto, uma subclasse é derivada, não é necessário redeclarar 
os atributos e métodos já definidos. Em outras palavras, por meio da 
herança, a subclasse herda tais atributos e métodos automaticamente, 
permitindo a reutilização do código já pronto. 
Assim, é preciso, somente, declarar os atributos ou métodos restritos 
da subclasse, o que torna o processo de desenvolvimento mais ágil, além 
de facilitar as manutenções futuras, pois, em caso de alteração, será ne-
cessário alterar, somente, o método da superclasse para que todas as sub-
classes estejam, também, atualizadas. A Figura 6 apresenta um exemplo 
de herança, explicitando os papéis de superclasse e subclasse e, também, 
apresenta o símbolo de herança da UML, uma linha que liga as classes 
com um triângulo que toca a superclasse:
U
N
ID
A
D
E
 1
24
Figura 6 - Exemplo de herança / Fonte: os autores.
A figura apresentada mostra a superclasse cliente com os atributos nome, en-
dereço, cidade, UF e CEP, bem como os métodos incluirNovoCliente() e atuali-
zarCliente(). A subclasse PessoaFisica herda esses atributos e métodos, além de 
possuir os atributos CPF e RG e o método validarCPF(). A seta que aponta para 
a superclasse cliente indica a herança. A subclasse PessoaJuridica herda, também, 
todos os atributos e métodos da superclasse cliente, além de possuir os atributos 
CNPJ, inscrição_estadual e razão_social e o método validarCNPF().
Quando olhamos para a Figura 6, notamos que a classe cliente é a mais gené-
rica e as classes PessoaFisica e PessoaJuridica são as mais especializadas. Então, 
podemos afirmar que generalizamos quando partimos das subclasses para a su-
perclasse e especializamos quando fazemos o contrário, ou seja, quando partimos 
da superclasse para as subclasses.
Polimorfismo
O conceito de polimorfismo está associado à herança, pois trabalha com a re-
declaração de métodos previamente herdados por uma classe. Esses métodos, 
embora parecidos, diferem-se, de alguma forma, da implementação utilizada na 
Cliente
- nome : string
- endereço : string
- cidade : string
- UF : char
- CEP : char
+ incluirNovoCliente() : void
+ atualizarCliente() : void
- cnpj : int
- inscricao_estadual : int
- razão_social: string
+ validarCnpj() : void
PessoaJurídica
- cpf: int
- RG : int
+ validarCpf() : void
PessoaFísica
U
N
IC
E
S
U
M
A
R
25
superclasse, sendo necessário implementá-los, novamente, na subclasse. Todavia, 
a fim de não ter que alterar o código-fonte, acrescentando uma chamada a um 
método com nome diferente, redeclara-se o método com o mesmo nome decla-
rado na superclasse (GUEDES, 2007).
De acordo com Lima (2009), o polimorfismoé o princípio em que classes 
derivadas (as subclasses) e uma mesma superclasse podem chamar métodos que 
têm o mesmo nome (ou a mesma assinatura), mas que possuem comportamentos 
diferentes em cada subclasse, produzindo resultados diferentes, dependendo de 
como cada objeto implementa o método.
Em outras palavras, podem existir dois ou mais métodos com a 
mesma nomenclatura, diferenciando-se na maneira como foram im-
plementados. O sistema é o responsável por verificar se a classe da 
instância em questão possui o método declarado nela própria ou se o 
herda de uma superclasse (GUEDES, 2007).
Por ser um exemplo bastante claro, para ilustrar o polimorfismo, 
apresentamos a Figura 7:
Figura 7 - Exemplo de poliformismo / Fonte: os autores.
No exemplo apresentado, há uma classe geral chamada Conta_Comum 
(que, neste caso, é a superclasse), a qual possui um atributo chamado 
saldo, que contém o valor total depositado em determinada instância 
da classe, e um método chamado saque. Esse método, somente, diminui 
o valor a ser debitado do saldo da conta se este possuir valor suficiente. 
Caso contrário, a operação não poderá ser realizada, ou seja, o saque deve 
ser recusado pelo sistema (GUEDES, 2007).
Conta_Comum
- saldo : double
+ saque() : void
- aniversario : date
Conta_Poupança
- limite : double 
+ saque() : void
Conta_Especial
U
N
ID
A
D
E
 1
26
5 
DIAGRAMA DE 
CLASSES
Os diagramas de classe são usados no desenvolvimento de um modelo de sistema orien-
tado a objetos para mostrar as classes de um sistema e as associações entre elas. Em pou-
cas palavras, uma classe de objeto pode ser pensada como a definição geral de um tipo 
de objeto do sistema. Uma associação é um link entre classes que indica algum relaciona-
mento entre elas. Consequentemente, cada classe pode precisar de certo conhecimento 
de sua classe associada. Quando você está desenvolvendo modelos durante os estágios 
explorando Ideias
O diagrama de classes tem como objetivo permitir a visualização das classes uti-
lizadas pelo sistema e como elas se relacionam, apresentando a visão estática de 
como estão organizadas, preocupando-se, apenas, em definir a sua estrutura lógica 
(GUEDES, 2007). Ainda, de acordo com o estudioso, um diagrama de classes pode 
ser utilizado para modelar o modelo lógico de um banco de dados, parecendo-se, 
neste caso, com o diagrama de entidade-relacionamento (o modelo entidade-re-
lacionamento, o qual você estuda na disciplina de banco de dados). No entanto 
deve ficar bem claro que o diagrama de classes não é utilizado, unicamente, para 
esta finalidade, e que uma classe não corresponde, necessariamente, a uma tabela.
U
N
IC
E
S
U
M
A
R
27
iniciais do processo de engenharia de software, os objetos representam algo no mundo real, 
como um paciente, uma receita médica, um médico etc. Enquanto uma aplicação é desenvol-
vida, geralmente, é necessário definir objetos adicionais de implementação que são usados 
para fornecer a funcionalidade requerida do sistema. 
Fonte: adaptado de Sommerville (2011, p. 90).
Estrutura da classe
Uma classe pode representar o repositório lógico dos atributos de uma tabe-
la, mas a classe não é a tabela. Isto se deve ao fato de que os atributos de seus 
objetos são armazenados em memória enquanto uma tabela armazena os seus 
registros fisicamente, em disco. Podemos definir classe como a descrição de 
uma coleção de objetos que possuem propriedades (atributos, métodos e as-
sociações), conforme mostra a Figura 8:
Figura 8 - Estrutura da classe / Fonte: os autores.
Relacionamentos
As classes não trabalham sozinhas. Pelo contrário, elas colaboram umas com 
as outras, por meio de relacionamentos (MELO, 2004). No diagrama de clas-
ses, temos alguns tipos de relacionamentos, como o de associação (que pode ser 
unária ou binária), de generalização ou de agregação, por exemplo. Na sequência, 
detalharemos esses e outros tipos.
+ Nome : string = Fernando
+Idade : int = 18
+ andar(entrada direção: Direção) : bool
+ dormir() : bool
Pessoa
Nome da classe 
Métodos
São as operações que podem ser
executadas sobre um objeto
Atributos e tipo de dado
Informação associada a
um objeto
U
N
ID
A
D
E
 1
28
Associação
De acordo com Melo (2004), a associação é um relacionamento que conecta duas 
ou mais classes, demonstrando a colaboração entre as instâncias de classe. Pode, 
também, existir o relacionamento de uma classe com ela mesma e, neste caso, 
tem-se uma associação unária ou reflexiva. A seguir, apresentaremos, na Figura 
9, um exemplo de uma associação entre classes:
Figura 9 - Exemplo de associação / Fonte: os autores.
Associação unária ou reflexiva
Segundo Guedes (2007), a associação 
unária ocorre quando existe o rela-
cionamento da instância de uma clas-
se com instâncias da mesma classe, 
conforme ilustra a Figura 10:
No exemplo apresentado, temos a classe funcionário, cujos atributos são código 
e nome bem como o código do possível chefe do funcionário. Pelo fato de esse 
chefe, também, ser um funcionário, a associação chamada “chefia” indica possí-
vel relação entre uma ou mais instâncias dessa classe com outras instâncias da 
mesma classe, ou seja, tal associação determina que um funcionário pode ou não 
chefiar outros. Além disso, essa associação faz com que a classe possua o atributo 
codChefe para armazenar o código do funcionário, atributo esse que é o respon-
sável pela instância do funcionário em questão. Desse modo, após consultar uma 
instância da classe funcionário, pode-se utilizar o atributo codChefe da instância 
consultada para pesquisar outra instância da classe (GUEDES, 2007).
- Codigo : int
- Nome : char
+ CalcPreco() : void
+ CalcImposto() : void
Produto
- NumeroVenda: int
+ Data() : int
Venda
Associação
0..* 0..*
- codigo : int
- nome : char
- codChefe : int
Funcionario
Chefia
0..*
Figura 10 - Exemplo de associação unária.
Fonte: os autores. 
U
N
IC
E
S
U
M
A
R
29
Associação binária
A associação binária conecta duas classes por meio de uma reta que liga uma 
classe a outra. A Figura 11 demonstra um exemplo de associação binária:
Figura 11 – Exemplo de associação binária / Fonte: os autores. 
No exemplo, um objeto da classe cidade pode ou não se relacionar com instâncias 
da classe cliente, conforme demonstra a multiplicidade 0..*. Entretanto, se existir 
um objeto da classe cliente, ele terá que se relacionar com um objeto da classe 
cidade, pois, pelo fato de que não foi definida a multiplicidade na extremidade 
da classe cidade, isto significa que ela é 1..1. Após termos explicado os relaciona-
mentos em um diagrama de classes, explicaremos o conceito de multiplicidade.
Agregação
Uma agregação pode ocorrer, somente, entre duas classes. De acordo com as re-
gras da UML, esse tipo de relacionamento ou associação é identificável a partir da 
notação de uma linha sólida entre duas classes: a classe denominada “todo-agre-
gado” recebe um diamante vazio, enquanto a outra ponta da linha é ligada à classe 
denominada “parte-constituinte”. Ambas podem “viver” de forma independente, 
ou seja, não existe ligação forte entre as duas. Objetos da parte constituinte ou da 
parte agregada são independentes em termos de vida, mas ambas são partes do 
todo único. Essa análise dependerá do domínio do problema em estudo.
Para sabermos se um relacionamento é de agregação, basta perguntarmos se, em 
primeiro lugar, ele comporta a estrutura todo-parte. Em seguida, questionamos se o 
objeto constituinte-parte “vive” sem o objeto agregado. Se a resposta for sim a ambas 
Cliente
- nome : string
- sexo : char
- data_nascimento : Date 
- endereco : String
- CEP : int
- nome : String
- UF : String
- DDD : int
Cidade
0..*
U
N
ID
A
D
E
 1
30
as perguntas, teremos uma agregação. A Figura 12 apresenta a notação para esta se-
mântica. Em determinado domínio de problema que trata de apartamentos e con-
domínios, observamosque um apartamento tem depósitos. Quando nos referimos 
a um depósito, podemos perguntar a qual apartamento ele pertence. Por outro lado, 
determinado proprietário pode ter decidido vender 
um depósito para alguém que sequer mora no prédio. 
Assim, teremos os dois objetos, neste exemplo, viven-
do separadamente, sem incômodo algum.
Poderíamos ter a situação em que um aparta-
mento é interditado ou passa por extensa reforma. 
Durante algum tempo, não temos movimentação 
naquele local, mas o depósito que faz parte daquele 
jogo apartamento-depósito continua sendo usado 
livremente. Assim, o mesmo exemplo valeria para 
garagens de um apartamento:
Composição
Uma composição ocorre quando temos uma situação semelhante à da agrega-
ção entre duas classes, mas os objetos da classe parte não podem viver quando 
o todo é destruído. Esse tipo de relacionamento é identificável pela notação de 
uma linha sólida entre duas classes: a classe denominada todo-composta, a qual 
recebe um diamante preenchido, enquanto a outra ponta da linha é ligada à classe 
denominada “parte-componente”.
Ambas as classes “vivem” unidas de forma dependente, ou seja, existe uma ligação 
forte entre as duas. Os objetos-parte não podem ser destruídos por um objeto diferen-
te do objeto-todo ao qual estão relacionados (GUEDES, 2011). Essa análise depen-
derá do domínio do problema em estudo. Para sabermos se um relacionamento é de 
composição, basta perguntarmos se, em primeiro lugar, cabe a estrutura todo-parte. 
Em seguida, questionamos se o objeto parte “vive” sem o objeto todo. Se a resposta for 
sim para a primeira pergunta e não para segunda, teremos uma composição. 
clsApartamento
- dMetragem : double
- IcountApartamento: double
+ obterMetragem() : void
+ obterNrAptsInstanciados() : int
clDeposito
Figura 12 - Uma agregação en-
tre duas classes.
Fonte: os autores.
U
N
IC
E
S
U
M
A
R
31
A Figura 13 apresenta uma visão da notação para esse tipo de relacio-
namento. Em relação a este domínio de problema, precisamos pensar o pré-
dio como um todo. Isso parece plausível, pois, nesse domínio de problema, 
necessariamente, um prédio deveria existir para que haja um apartamento. 
Caso não pudesse qualificar um prédio, nada poderia ser feito em relação 
àquele apartamento. Não se pode fazer nada com um apartamento, vender 
ou alugar, enquanto ele não possuir um endereço. O endereço é o do pré-
dio, o apartamento possui, apenas, complemento. Assim, para os fins deste 
software, não seria possível instanciar um objeto clsApartamento, caso não 
fosse designado um objeto clsPredio:
Figura 13 - Composição entre duas classes / Fonte: os autores. 
Generalização/especialização
Esta associação identifica as classes-mãe (superclasses), as quais são chamadas 
gerais, e as classes-filhas (subclasses), as chamadas especializadas, demonstrando 
a ocorrência de herança e, possivelmente, de métodos polimórficos nas classes 
especializadas. A seguir, na Figura 14, há um exemplo entre classes que demonstra 
o uso de generalização/especialização:
clsApartamento
- dMetragem : double
- IcountApartamento: int
+ obterMetragem()
+ obterNumAptsInstanciados() : int
clsDeposito
clsPredio
- Nome : String
- Endereco : String
U
N
ID
A
D
E
 1
32
Figura 14 - Generalização/especialização entre duas classes.
Fonte: Guedes (2011, p. 114).
Multiplicidade
De acordo com Guedes (2007), a multiplicidade determina o número mínimo e 
máximo de instâncias envolvidas em cada uma das extremidades da associação, 
permitindo, também, especificar o nível de dependência de um objeto com os ou-
tros. Quando não existe multiplicidade explícita, entende-se que ela é 1..1, o que 
significa que, somente, uma instância dessa extremidade da associação relaciona-se 
com as instâncias da outra extremidade. A Tabela 1, a seguir, demonstra alguns dos 
diversos valores de multiplicidade que podem ser utilizados em uma associação:
Conta_Comum
# nro_conta : long
# dt_abertura : Date
# dt_encerramento : Date
# situracao : int
# senha : int
# saldo : double
+ abrir_conta(int : int) : long
+ consultar_Conta(long : int) : int
+ validar_Senha(int : int) : int
+ saldo_Conta() : double
+ extrato_Conta() : String
+ sacar_Valor(double : int) : int
+ depositar_Valor(long : int, double : int) : int
+ encerrar_Conta() : int
- limite_conta : double 
+ abrir_conta(int : int, double : int) : long
+ sacar_valor(double : int) : int
+ juros_Conta(double : int) : double
Conta_Especial
- dt_aniversario : Date
+ renda_conta(Date : int, double : int) : double
Conta_Poupanca
U
N
IC
E
S
U
M
A
R
33
Multiplicidade Significado
0..1
No mínimo, zero (nenhum), no máximo, um. Indica que os 
objetos das classes associadas não precisam, obrigatoria-
mente, estar relacionados, mas, se houver relacionamento, 
indica que apenas uma instância da classe se relaciona com 
as instâncias da outra classe.
1..1
Um e somente um. Indica que apenas um objeto da classe 
se relaciona com os objetos da outra classe.
0..*
No mínimo, nenhum, no máximo, muitos. Indica que pode ou 
não haver instâncias da classe participando do relacionamento.
*
Muitos. Indica que muitos objetos da classe estão envolvi-
dos no relacionamento.
1..*
No mínimo, um, no máximo, muitos. Indica que há, pelo 
menos, um objeto envolvido no relacionamento e que pode 
haver muitos objetos envolvidos.
2..5
No mínimo, dois, no máximo, cinco. Indica que existem, pelo 
menos, duas instâncias envolvidas no relacionamento e que 
podem ser três, quatro ou cinco as instâncias envolvidas, 
porém não mais do que isso.
Tabela 1 - Exemplos de multiplicidade / Fonte: adaptada de Guedes (2011, p. 108).
As associações que possuem multiplicidade do tipo muitos (*), em qualquer de suas 
extremidades, forçam a transmissão do atributo-chave na classe da outra extremida-
de da associação. Entretanto esse atributo-chave não aparece desenhado na classe.
Figura 15 – Multiplicidade / Fonte: os autores.
Pessoa Empresa
1..* *
trabalha para
multiplicidade associação
U
N
ID
A
D
E
 1
34
Classe associativa
Quando um relacionamento possui multiplicidade, ou seja, muitos (*) em suas 
duas extremidades, é necessário criar uma classe associativa para guardar os ob-
jetos envolvidos nessa associação. Na classe associativa, são definidos o conjunto 
de atributos que participam da associação, e não as classes que participam do 
relacionamento. Nesse caso, pelo menos os atributos-chave devem fazer parte da 
classe associativa, mas ela, também, pode ter atributos próprios.
Uma classe associativa é representada por uma reta tracejada que parte do 
meio da associação e atinge uma classe. A Figura 16 apresenta um exemplo de 
classe associativa que possui atributos próprios, além dos atributos-chave das 
classes que participam da associação. Contudo é necessário reforçar que, neste 
caso, esses atributos-chave não são representados no diagrama.
Figura 16 - Exemplo de classe associativa / Fonte: os autores.
No exemplo apresentado, uma instância da classe curso pode se relacionar com 
muitas instâncias da classe disciplina, bem como uma instância da classe disci-
plina pode se relacionar com muitas instâncias da classe curso. Como existe a 
multiplicidade nas extremidades de ambas as classes da associação, não há como 
reservar atributos para armazenar as informações decorrentes da associação, já 
que não é possível determinar um limite para a quantidade de disciplinas que 
um curso pode ter e nem saber a quantos cursos uma disciplina pode pertencer.
Assim, é preciso criar uma classe para guardar essa informação, além das 
informações próprias da classe, que são a carga horária da disciplina no curso e a 
Curso
- nome : int
- area : int
Disciplina_Curso
- carga_horaria : int
- serie : int
Disciplina
- nome : int
Disciplina_Curso
1..* 1..*
U
N
IC
E
S
U
M
A
R
35
série a qual essa disciplina estará vinculada. Os atributos-chave das classescurso 
e disciplina são transmitidos de forma transparente pela associação, não sendo 
necessário, portanto, escrevê-los como atributos da classe associativa.
Segundo Guedes (2007), as classes associativas podem ser substituídas por 
classes normais, que, neste caso, são chamadas de classes intermediárias, mas 
que desempenham, exatamente, a mesma função das associativas. A Figura 17 
mostra o mesmo exemplo da figura anterior, porém com a classe intermediária 
no lugar da classe associativa:
Figura 17 - Exemplo de classe intermediária / Fonte: os autores.
Curso
- nome : int
- area : int
Disciplina_Curso
- carga_horaria : int
- serie : int
Disciplina
- nome : int
1..* 1..*
U
N
ID
A
D
E
 1
36
CONSIDERAÇÕES FINAIS
No decorrer desta unidade, estudamos a importância da modelagem de um siste-
ma e como ela é a parte fundamental de todas as atividades de desenvolvimento, 
dentro de um processo de software, as quais levam à implantação de um bom 
software. Esses modelos, normalmente, são representados por meio de diagramas 
em que é utilizada uma notação gráfica, a qual, em nosso caso, foi a UML (Unified 
Modeling Language ou Linguagem de Modelagem Unificada).
Iniciamos a unidade aprendendo que a modelagem de software se baseia na 
utilização de notações gráficas e textuais com o objetivo de construir modelos que 
representem as partes essenciais de um sistema. Na sequência, estudamos alguns 
conceitos das Ferramentas CASE (Computer-Aided Software Engineering) e 
da UML. Aprendemos, também, que todos os artefatos de software produzidos 
durante a modelagem, dentre eles, o diagrama de classe, podem ser usados como 
base para as fases seguintes do ciclo de vida do programa. 
Aprendemos que, pelo fato de a UML ser, totalmente, baseada no paradigma 
de Orientação a Objetos (OO), foi necessário, para compreendê-la, estudar alguns 
dos conceitos relacionados a tal orientação. Portanto, na sequência, abordamos 
os conceitos básicos desse paradigma para entender, por meio de elementos, a 
estrutura do sistema.
Por último, relembramos o diagrama de classes, sendo o mais importante e 
utilizado da UML, pois é ele que define a estrutura das classes identificadas para 
o sistema, mostrando os atributos e os métodos de cada uma das classes bem 
como os seus relacionamentos. 
Na próxima unidade, você estudará conceitos de encapsulamento e mo-
dificadores de acesso denominados public, protected e private. Entenderá 
a diferença dos modificadores static, abstract e final e, também, o que são 
os construtores de classes. 
Preparados para seguir em frente? Bons estudos!
37
na prática
1. Uma classe é um conjunto de objetos que possuem os mesmos tipos de caracterís-
ticas e comportamentos, sendo representada por um retângulo que pode possuir 
até três divisões. Partindo desse conceito, elabore um diagrama de classes com 
duas classes que tenham as características citadas a seguir. Lembre-se que classes 
não trabalham sozinhas, portanto, construa, entre elas, um relacionamento 1..* (no 
mínimo, um, no máximo, muitos):
Nome da classe:
FUNCIONÁRIO
Descrição:
Contém dados cadastrais dos funcionários
Campo Tipo Visibilidade Chave Descrição
Matricula Integer Pública PK Matrícula
CpfCnpj String Pública CPF ou CNPJ
NomeFunc String Pública --- Nome do funcionário
DtAdmissao Date Pública --- Data da admissão
Métodos:
+IncluirNovoFunc
+BuscarFunc
+ExcluirFunc
Nome da Classe:
DEPENDENTE
Descrição:
Contém dados cadastrais do dependente
Campo Tipo Visibilidade Chave Descrição
IdDep Integer Privada PK Número do dependente
NomeDep String Privada --- Nome do dependente
DtNasci-
mento
Date Privada --- Data de nascimento
IdFunc Integer Pública FK Código do funcionário
Métodos:
+IncluirNovoDep
+ExcluirDep
38
na prática
2. Faça um diagrama de classes para um sistema de locações de ônibus, levando em 
consideração os seguintes requisitos:
• A empresa tem muitos ônibus. Cada ônibus tem os seguintes atributos: número 
de placa, cor, ano, tipo de combustível, número de portas, quilometragem, Re-
navame valor de locação.
• Cada ônibus tem um modelo e uma marca, mas um modelo pode relacionar-se 
a muitos ônibus e uma marca pode referir-se a muitos modelos, embora cada 
modelo só tenha uma marca específica.
• Um ônibus pode ser alugado por muitos clientes, em momentos diferentes, e 
um cliente pode alugar muitos ônibus. É preciso saber quais estão locados ou 
não. Sempre que locar um ônibus, é necessário armazenar a data e a hora de 
sua locação e, quando for devolvido, a data e a hora da devolução.
Com base nesse cenário, identifique as classes, os atributos, os métodos 
e os relacionamentos.
3. O diagrama de classe é uma representação da estrutura e das relações das classes 
que servem de modelo para objetos. Partindo disso, analise o diagrama de classe, 
a seguir, e assinale a alternativa correta:
a) Entre as entidades ônibus e passageiro, temos um rela-
cionamento de composição.
b) Entre as entidades ônibus e passageiro, temos um rela-
cionamento de agregação.
c) Entre as entidades ônibus e passageiro, temos um relacio-
namento de generalização/especialização (herança).
d) Entre as entidades ônibus e passageiro, temos um rela-
cionamento unário.
e) Entre as entidades ônibus e passageiro, temos um rela-
cionamento de realização.
Onibus
Passageiro
39
na prática
4. Maria controla, em Excel, a sua lista mensal de compras de produtos. Na planilha, 
ela cadastra: 
• Nome do produto.
• Unidade de compra (quilos, litros, metros etc.).
• Quantidade prevista para o mês.
• Quantidade comprada.
• Preço estimado (que é atualizado todo mês).
• Valor total da compra.
A quantidade comprada pode variar em função da sobra do produto de um mês 
para o outro ou da necessidade de um gasto menor ou maior no mês. Com base 
nesse cenário, identifique as classes, os atributos, os métodos e os relacionamentos. 
5. Os símbolos menos (-) e mais (+), na frente dos atributos e métodos, representam 
a sua visibilidade. Esta, por sua vez, é utilizada para indicar o nível de acessibilidade 
de determinado atributo ou método, sendo, sempre, representada à esquerda. 
A partir da informação apresentada, descreva os principais três modos de visibilidade 
utilizados na UML.
40
aprimore-se
A UML – Unified Modeling Language ou Linguagem de Modelagem Unificada – é 
uma linguagem visual utilizada para modelar softwares baseados no paradigma de 
orientação a objetos. É uma linguagem de modelagem de propósito geral que pode 
ser aplicada a todos os domínios de aplicação. Essa linguagem tornou-se, nos úl-
timos anos, a linguagem-padrão de modelagem adotada internacionalmente pela 
indústria de engenharia de software.
Deve ficar bem claro, porém, que a UML não é uma linguagem de programa-
ção, e sim uma linguagem de modelagem, uma notação, cujo objetivo é auxiliar os 
engenheiros de software a definirem as características do sistema, tais como seus 
requisitos, seu comportamento, sua estrutura lógica, a dinâmica de seus proces-
sos e até mesmo suas necessidades físicas em relação ao equipamento sobre o 
qual o sistema deverá ser implantado. Tais características podem ser definidas por 
meio da UML antes do software começar a ser realmente desenvolvido. Além disso, 
cumpre destacar que a UML não é um processo de desenvolvimento de software e 
tampouco está ligada a um de forma exclusiva, sendo totalmente independente, po-
dendo ser utilizada por muitos processos de desenvolvimento diferentes ou mesmo 
da forma que o engenheiro considerar mais adequada. 
A UML surgiu da união de três métodos de modelagem: o método de Booch, o 
método OMT (Object Modeling Technique) de Jacobson, e o método OOSE (Objec-
t-Oriented Software Engineering) de Rumbaugh. Estes eram, até meados da déca-
da de 1990, os métodos de modelagem orientada a objetos mais populares entre 
os profissionais da área de desenvolvimento de software. A união desses métodos 
contoucom o amplo apoio da Rational Software, que a incentivou e financiou. O 
esforço inicial do projeto começou com a união do método de Booch ao OMT de 
Jacobson, o que resultou no lançamento do Método Unificado no final de 1995. Logo 
em seguida, Rumbaugh juntou-se a Booch e Jacobson na Rational Software, e seu 
método OOSE começou também a ser incorporado à nova metodologia. O trabalho 
41
aprimore-se
de Booch, Jacobson e Rumbaugh, conhecidos popularmente como “Os Três Ami-
gos”, resultou no lançamento, em 1996, da primeira versão da UML propriamente 
dita. Tão logo a primeira versão foi lançada, muitas empresas atuantes na área de 
modelagem e desenvolvimento de software passaram a contribuir para o projeto, 
fornecendo sugestões para melhorar e ampliar a linguagem. Finalmente, a UML foi 
adotada, em 1997, pela OMG (Object Management Group ou Grupo de Gerencia-
mento de Objetos), como uma linguagem-padrão de modelagem. 
A versão 2.0 da linguagem foi oficialmente lançada em julho de 2005, encontran-
do-se, atualmente, na versão 2.3 beta. A documentação oficial da UML pode ser con-
sultada no site da OMG em www.omg.org ou mais exatamente em www.uml.org.
POR QUE MODELAR SOFTWARE?
Qual a real necessidade de se modelar um software? Muitos “profissionais” podem 
afirmar que conseguem determinar todas as necessidades de um sistema de in-
formação de cabeça, e que sempre trabalharam assim. Qual a real necessidade de 
se projetar uma casa? Um pedreiro experiente não é capaz de construí-la sem um 
projeto? Isso pode ser verdade, mas a questão é muito mais ampla, envolvendo 
fatores extremamente complexos, como levantamento e análise de requisitos, pro-
totipação, tamanho do projeto, complexidade, prazos, custos, documentação, ma-
nutenção e reusabilidade, entre outros.
Existe uma diferença gritante entre construir uma pequena casa e construir um 
prédio de vários andares. Obviamente, para se construir um edifício é necessário, 
em primeiro lugar, desenvolver um projeto muito bem-elaborado, cujos cálculos 
têm de estar extremamente corretos e precisos. Além disso, é preciso fornecer uma 
estimativa de custos, determinar em quanto tempo a construção estará concluída, 
avaliar a quantidade de profissionais necessária à execução da obra, especificar a 
42
aprimore-se
quantidade de material a ser adquirida para a construção, escolher o local onde o 
prédio será erguido etc. Grandes projetos não podem ser modelados de cabeça, 
nem mesmo a maioria dos pequenos projetos pode sê-lo, exceto, talvez, aqueles 
extremamente simples.
Na realidade, por mais simples que seja, todo e qualquer sistema deve ser mode-
lado antes de se iniciar sua implementação, entre outras coisas, porque os sistemas 
de informação frequentemente costumam ter a propriedade de “crescer”, isto é, au-
mentar em tamanho, complexidade e abrangência. Muitos profissionais costumam 
afirmar que sistemas de informação são “vivos”, porque nunca estão completamen-
te finalizados. Na verdade, o termo correto seria “dinâmicos”, pois normalmente os 
sistemas de informação estão em constante mudança. Tais mudanças são devidas a 
diversos fatores, como, por exemplo:
• Os clientes desejam constantemente modificações ou melhorias no sistema.
• O mercado está sempre mudando, o que força a adoção de novas estraté-
gias por parte das empresas e, consequentemente, de seus sistemas.
• O governo seguidamente promulga novas leis e cria novos impostos e alí-
quotas ou, ainda, modifica as leis, os impostos e alíquotas já existentes, o 
que acarreta a manutenção no software.
Assim, um sistema de informação precisa ter uma documentação extremamente de-
talhada, precisa e atualizada para que possa ser mantido com facilidade, rapidez e 
correção, sem produzir novos erros ao corrigir os antigos. Modelar um sistema é uma 
forma bastante eficiente de documentá-lo, mas a modelagem não serve apenas para 
isso: a documentação é apenas uma das vantagens fornecidas pela modelagem. 
Fonte: Guedes (2011, p. 19-21). 
43
eu recomendo!
UML 2 – Uma Abordagem Prática
Autor: Gilleanes Thorwald Araújo Guedes
Editora: Novatec
Sinopse: a UML – Unified Modeling Language ou Linguagem de 
Modelagem Unificada – é uma linguagem utilizada para modelar 
softwares baseados no paradigma de orientação a objetos, aplica-
da, principalmente, durante as fases de análise de requisitos e de 
projeto de software. A UML consagrou-se como a linguagem-padrão de modelagem 
adotada, internacionalmente, pela indústria de Engenharia de Software e, assim, há 
amplo mercado para profissionais que a dominam. Este livro procura ensinar ao 
leitor, por meio de exemplos práticos, como modelar softwares pela UML. A lingua-
gem é ensinada mediante a apresentação de seus muitos diagramas, detalhando o 
propósito e a aplicação de cada um deles e os elementos que os compõem, as suas 
funções e formas de aplicação. A obra enfatiza, ainda, a importância da UML para a 
Engenharia de Software, além de abordar o paradigma de orientação a objetos, um 
conceito imprescindível para a compreensão correta da linguagem. 
livro
44
eu recomendo!
Este vídeo mostra uma introdução aos conceitos de orientação a objetos.
http://www.youtube.com/watch?v=MnJLeYAno4o&feature=relmfu.
O vídeo mostra a importância da modelagem de sistemas bem como da elabora-
ção do diagrama de casos de uso.
http://www.youtube.com/watch?v=hfN6n5fJfLc&feature=relmfu.
conecte-se
UML – Guia do Usuário
Autor: Grady Booch, James Rumbaugh e Ivar Jacobson
Editora: Campus
Sinopse: há quase 10 anos, a Unified Modeling Language (UML) é o 
padrão para visualizar, especificar, construir e documentar os arte-
fatos de um sistema de software. A UML 2.0 vem para assegurar as 
contínuas popularidade e viabilidade da linguagem. As suas simpli-
cidade e expressividade permitem que os usuários modelem tudo, desde sistemas 
empresariais de informação, passando por aplicações distribuídas baseadas na 
Web até sistemas embutidos de tempo real. Nesta nova edição, totalmente revista, 
os criadores da linguagem fornecem um tutorial dos aspectos centrais da UML. 
Começando com um modelo conceitual da UML, o livro aplica, progressivamente, 
a linguagem em uma série de problemas de modelagem cada vez mais complexos, 
usando diversos domínios de aplicação. A abordagem em tópicos é recheada de 
exemplo, o que fez da primeira edição um recurso indispensável. Entretanto, o con-
teúdo reflete as mudanças na notação e no uso exigidos pela UML 2.0.
livro
2
PLANO DE ESTUDO 
A seguir, apresentam-se os tópicos que você estudará nesta unidade: • O que é encapsulamento? 
• Modificadores de acesso: default, public, protected e private • Utilizando modificadores de acesso 
(getters e setters) • Modificadores static, abstract e final • Construtores de classe.
OBJETIVOS DE APRENDIZAGEM 
• Entender o conceito de encapsulamento • Estudar os modificadores de acesso default, public, protec-
ted e private • Controlar o acesso a métodos, atributos e construtores por meio de modificadores • En-
tender a diferença dos modificadores static, abstract e final • Entender o que são construtores de classes.
MODIFICADORES
JAVA E
ENCAPSULAMENTO
PROFESSORES 
Dr. Edson Alves de Oliveira Junior
Me. Andre Abdala Noel
Me. Márcia Cristina Dadalto Pascutti
Me. Rafael Alves Florindo 
Esp. Victor de Marqui Pedroso
Esp. Janaina Aparecida de Freitas 
INTRODUÇÃO
Caro(a) aluno(a), após estudarmos a importância da modelagem de 
um sistema em UML, e como ela é a parte fundamental de todas as 
atividades dentro de um processo de software, nesta segunda unidade, 
você verá a revisão dos conceitos de encapsulamento, de modificadores 
de acesso e construtores em Java. 
A ideia de encapsulamento remete ao fato de que é possível agru-
par estados e comportamentos de um objeto em um mesmo módulo 
e, ainda, controlar as suas propriedades e o seu acesso, ou seja, trata 
dos padrões de visibilidade de acessos para as classes,os atributos e os 
métodos. Para estudar o encapsulamento, escreveremos métodos de 
acesso que são mais conhecidos como modificadores de acesso. Estes 
atuarão em elementos de uma classe, utilizando os chamados métodos 
setters (armazenamento) e getters (resgate).
Nos modificadores de acesso setters e getters, a linguagem Java permite 
o uso dos modificadores static, final e abstract. O modificador static permite 
que um método de uma classe seja invocada sem ter a instância de uma. O 
modificador final bloqueará a herança da classe ou o reuso de um método 
em outra classe. O modificador abstract permite modelar uma classe de 
forma que ela seja um modelo para as outras que a estendem.
Por fim, abordaremos o momento em que uma classe é instanciada, 
ou seja, quando criamos um objeto de uma classe que, automaticamente, 
é executado o seu método construtor, que pode inicializar atributos ou 
outras instruções essenciais para o início da classe. Dessa forma, con-
trolaremos como os objetos de uma classe serão inicializados e de qual 
forma podemos melhor aproveitá-los.
Para mostrar a você como utilizar estes recursos, empregaremos alguns 
exemplos que usam essas técnicas de modificadores de acesso e de cons-
trutores de classe. Discutiremos, ao longo da unidade, um exemplo para a 
apresentação do tema e, também, outro exemplo, em que será construído 
um projeto completo, desenvolvido com as técnicas apresentadas.
U
N
IC
E
S
U
M
A
R
47
1 
O QUE É 
ENCAPSULAMENTO?
Classes (e seus objetos) encapsulam, isto é, contêm seus atributos e métodos. Os atri-
butos e métodos de uma classe (e de seu objeto) estão intimamente relacionados. Os 
objetos podem se comunicar entre si, mas eles, em geral, não sabem como outros ob-
jetos são implementados – os detalhes de implementação permanecem ocultos dentro 
dos próprios objetos. Esse ocultamento de informações, como veremos, é crucial à boa 
engenharia de software. 
Fonte: Deitel e Deitel (2017, p. 9). 
conceituando
Caro(a) aluno(a), quando se fala de encapsulamento, você, provavelmente, ima-
gina um objeto fechado, dentro de uma cápsula, e isto não é muito diferente 
na programação orientada a objetos, pois a ideia principal do encapsulamento 
envolve omitir os membros de uma classe, além de esconder como funcionam 
as rotinas ou as regras de negócio. Dessa forma, o programador deve se atentar 
às funcionalidades da classe, e não como ela foi implementada. Isto é bom, uma 
vez que há a expansão na modularidade do seu projeto.
Sendo assim, realizar o encapsulamento de um projeto é fundamental para a 
possibilidade de minimizar o impacto de problemas referentes a alterações do 
U
N
ID
A
D
E
 2
48
projeto, uma vez que não é preciso alterar uma regra de negócio em vários lugares, 
mas, sim, em apenas um lugar, já que tal regra está encapsulada.
Para exemplificar, focaremos no problema de realização de operações bancá-
rias em um caixa eletrônico. No caixa, é possível: sacar dinheiro, depositar, verifi-
car saldo, verificar extrato, pagar contas e fazer transferências. Para utilizar o caixa 
eletrônico, não é necessário conhecer como as operações foram implementadas 
em nível de programação, mas, sim, saber o que cada operação afeta em sua conta.
Analise a Figura 1, a seguir, e verifique a classe Conta, com atributos e méto-
dos para uma Conta Corrente. Note, por exemplo, que o método transferir rece-
be, como parâmetro, o número da conta 
(numContaDestino) e um valor a ser 
transferido (valor). Para utilizar esse 
método, o programador não precisa saber 
como o criador dessa classe o implemen-
tou, basta saber que esse método é respon-
sável por enviar um valor para outra conta 
corrente, e que essa transferência implica 
subtração do saldo da conta remetente.
Ainda em relação à Figura 1, que ilustra um diagrama de Classe UML, o símbo-
lo soma (+) indica que tanto os atributos quanto os métodos são públicos. Isso 
significa que eles podem ser acessados e modificados de qualquer outra classe 
do projeto, e isto não é uma boa prática de programação, uma vez que os seus 
atributos estão expostos e qualquer outro objeto pode alterar os valores dos ele-
mentos das classes, comprometendo, assim, a coesão do seu projeto. Por exemplo, 
na Figura 2: 
//Criação da referência a Conta
ContaCorrente cc = new Conta();
//Modificação do atributo saldo de forma direta
cc.saldo = 0;
System.out.println("Saldo Conta: R$"+cc.saldo);
Para solucionar este problema, faz-se necessária a utilização de modificadores de 
acesso, sendo que eles farão o papel de restringir ou autorizar o acesso a determi-
nados atributos ou métodos das classes, e isto será visto a partir da próxima seção.
Conta
+ saldo : float
+ titular : String
+ cpfTitular : String
+ numConta : int
+ sacar(valorSaque : float) : void
+ depositar(valorDep : float) : void
+ verificarSaldo() : void
+ transferir(numContaDestino : int, valor : int) : float 
Figura 1 - Classe Conta com atributos e 
métodos públicos / Fonte: os autores.
U
N
IC
E
S
U
M
A
R
49
2 
MODIFICADORES 
DE ACESSO:
Default, Public, Protected e 
Private
Segundo Deitel e Deitel (2017), projeto e pacotes de projeto são conceitos básicos da 
programação em Java: 
Um projeto é a base para o desenvolvimento em Java, é nele que estarão todos os paco-
tes, as classes, as interfaces, as imagens da sua aplicação (2017).
O rico conjunto do Java de classes predefinidas é agrupado em pacotes – chamados de 
grupos de classes. Estes são referidos como biblioteca de classes Java, ou Interface de 
Programação de Aplicativo Java (API Java). 
Fonte: os autores. 
conceituando
É a partir dos modificadores de acesso que poderemos restringir ou não o acesso 
aos atributos e métodos de uma classe. Na programação orientada a objetos, os 
modificadores de acesso mais utilizados são o public e o private.
Antes de abordarmos os modificadores, é importante frisar alguns conceitos 
básicos sobre a programação em Java: projeto e pacotes do projeto.
Quando trabalhamos com o Netbeans para a criação de um projeto, basta aces-
sarmos o menu “Arquivo” e, em seguida, selecionar a opção “Novo Projeto”. Feito 
isto, aparecerá uma tela, como você pode verificar na Figura 2, a seguir:
U
N
ID
A
D
E
 2
50
Figura 2 - Criando um projeto em Java no Netbeans / Fonte: os autores. 
Como o Netbeans é uma IDE que suporta diversas linguagens de programação, 
ao criar o projeto, é necessário, previamente, selecionar a linguagem e, em segui-
da, o tipo de projeto. Sendo assim, criaremos um Aplicativo Java selecionando a 
opção “Aplicativo Java”. Feito isso, uma nova tela solicitará o preenchimento do 
nome do projeto, como você pode verificar na Figura 3:
Figura 3 - Configurando o nome do projeto / Fonte: os autores.
U
N
IC
E
S
U
M
A
R
51
Após essas etapas, o seu projeto estará 
criado e poderá ser visualizado na Paleta 
“Projetos” do Netbeans, como pode ser ve-
rificado na Figura 4. Você pode notar que 
um projeto envolve pacotes e bibliotecas 
que, talvez, a sua aplicação necessite utilizar.
Figura 4 - Projeto em Java Fonte: os autores.
Para criar um novo pacote na pasta “Pacotes de código-fonte”, por exemplo, é neces-
sário clicar sobre a pasta com o botão direito e selecionar a opção: “Novo” -> “Pacote 
Java” e, em seguida, dar um nome ao seu novo pacote, como mostra a Figura 5.
Figura 5 - Criando um novo pacote Fonte: os autores.
Agora que você já entendeu o conceito de pacotes, iniciaremos a teoria sobre 
modificadores de acesso. Temos quatro deles: default, public, private e protected. 
O modificador default não precisa ser declarado, ou seja, atributos ou mé-
todos que não têm a declaração de um modificador de acesso são considerados 
default (do inglês, significa “padrão”). Como exemplo, você pode notar, no código, 
a criação de um atributo com modificador de acesso default. No pacote em que 
está localizada a classe criada, o atributo com essemodificador pode ser acessa-
do de forma direta por qualquer classe, agora, se a classe que instanciar a classe 
estiver em outro pacote, este não será acessível de forma direta.
U
N
ID
A
D
E
 2
52
//exemplo de atributo default
String valorTransitorio;
Atributos e métodos públicos (public) podem ser acessados e modificados de 
qualquer classe do projeto a partir da instância do objeto, ou seja, é possível, até 
de outros pacotes, ter acesso a atributos/métodos do tipo public, de forma direta. 
Para declarar esse tipo de modificador, é necessário utilizar a palavra reservada 
public antes de indicar o tipo de variável, isso pode ser verificado no exemplo de 
código-fonte, a seguir.
//exemplo de atributo public
public int idade;
//exemplo de método public
public int media(int valor1, int valor2){
 public float media;
 media = (valor1 + valor2) / 2;
 return media
}
Já atributos e métodos privados (private) são acessados somente pela pró-
pria classe, independentemente do pacote em que a classe esteja. O código 
fonte, a seguir, mostra como criar um atributo privado. Métodos privados 
só podem ser acessados pela própria classe, ou seja, eles não são visíveis e 
nem acessados por outros objetos.
//exemplo de atributo private
private String nomePessoa;
//exemplo de método private
private String[] splitNome(String n){
 return n.split("");
}
Outro modificador de acesso não tão comumente utilizado é o modificador pro-
tected (protegido, em português). Este funciona como um modificador público 
U
N
IC
E
S
U
M
A
R
53
para elementos que estão no mesmo pacote e, em outros pacotes, ele só é visível 
para classes que herdam a classe que possui o atributo protegido. A criação de 
atributos/métodos protegidos se faz por meio da palavra reservada protected 
antes da criação do atributo/método.
//exemplo de atributo protected
protected String nomeCliente;
//exemplo de método protected
protected String[] splitNome(String n){
 return n.split("");
}
Com base nas explicações dadas até aqui sobre os modificadores, é possível mon-
tar uma tabela que resume se o atributo/método é acessível ou não, dependendo 
de sua localização no projeto.
Modificador
Na própria 
classe
Em outro 
pacote
No mesmo 
pacote
Herança 
(em pacote 
diferente)
Public Acessível Acessível Acessível Acessível
Private Acessível Não Não Não
Protected Acessível Não Acessível Acessível
Default Acessível Não Acessível Não
Tabela 1 - Modificadores de acesso e suas visibilidades / Fonte: os autores.
É importante que você, como futuro(a) programador(a), entenda bem esta tabela 
e a tenha por perto para eventuais consultas. Sendo assim, na próxima seção, 
mostraremos, na prática, como utilizar os modificadores de acesso de modo a 
manter o encapsulamento de suas aplicações.
U
N
ID
A
D
E
 2
54
3 
UTILIZANDO MODIFICADORES
DE ACESSO 
(Getters e Setters)
Figura 6 - Exemplo de projeto, seus pa-
cotes e códigos-fonte / Fonte: os autores.
Tendo como base um projeto-exemplo de caixa eletrônico, cujo objetivo é realizar 
operações em contas bancárias, elucidaremos a utilização dos modificadores de 
acesso e, além disso, traremos o conceito dos getters e setters. Para isto, veja como 
foi projetada a aplicação na Figura 6:
Como você pode notar, o projeto possui 
três pacotes: “caixaeletronico”, “cliente” e 
“conta”. Cada pacote tem suas classes e 
suas particularidades que descrevere-
mos, uma a uma, a seguir.
O pacote “caixaeletronico” possui a 
classe “CaixaEletronico” e esta é a clas-
se inicial do projeto, é nela que se ini-
cia a execução da aplicação, pois esta 
contém o método principal (main) e 
ela será o nosso gerenciador de contas.
U
N
IC
E
S
U
M
A
R
55
O pacote “cliente” possui classes que estruturam os objetos Clientes que po-
derão ser pessoa física (Fisica.java) ou jurídica (Juridica.java). Será possível, tam-
bém, estruturar o formato do endereço de cada pessoa (Endereco.java).
Por fim, o pacote “conta” possui a classe Conta.java que armazena as infor-
mações de uma conta. No diagrama, a seguir, apresentado na Figura 7, é possível 
ter uma visão geral de cada classe do projeto. 
Figura 7 - Diagrama de classe do projeto de caixa eletrônico / Fonte: os autores.
Tendo, como base, os diagramas da Figura 7, primeiramente, entenderemos o 
Diagrama de Classes em questão: note que, antes dos nomes dos atributos e mé-
todos das classes, existe um sinal (-, + ou #), em UML. O sinal - significa que se 
trata de um atributo/método que utiliza modificador de acesso private, o sinal 
+ indica o modificador public, e o sinal # indica o modificador protected. Note, 
ainda, que as classes Física e Jurídica se ligam à classe Pessoa por meio de uma seta 
grande e vazia, e esta ligação significa que Física e Jurídica são “filhas” de Pessoa, 
ou seja, herdam todas as propriedades da classe Pessoa.
Pessoa
# nomePessoa : String
# endereco : Endereco
# telefone : String
Fisica
- cpf : String
Juridica
- cnpj : String
Juridica
- saldo : float
- numConta : int
- titular : Pessoa
- tipoConta : int
Endereco
- rua : String
- numero : int
- cidade : String
- uf : String
Caixa Eletronico
- c : Conta
- contasCadastradas : ArrayList<Conta>
+ sacar(valorSaque : float) : void
+ depositar(valorDep : oat) : void
+ verificarSaldo() : void
+ transferir(numContaDestino : Conta, valor : float) : void
U
N
ID
A
D
E
 2
56
Agora, você deve estar se perguntando: “se houve restrição do acesso a alguns atributos 
das classes apresentadas, como será realizada a alteração das informações, quando fo-
rem necessárias?”. A resposta é, relativamente, simples: basta criar métodos públicos que 
controlarão os acessos a essas variáveis, ou seja, será criada uma interface de acesso para 
cada atributo privado (private) da classe em questão, é aí que entra o conceito de getters 
e setters na programação orientada a objetos, e esse é um mecanismo de acesso a dados 
encapsulados.
pensando juntos
Sendo assim, aprenderemos a criar métodos que alteram os valores dos atri-
butos privados; a estes métodos damos o nome de setters, ou seja, eles “seta-
rão” os valores desses atributos. 
Para criar um método setter, primeiro, faz-se necessário analisar o tipo do 
atributo. Veremos, por exemplo, o atributo (saldo) da classe Conta; por se tratar 
de um do tipo float (real), o método para setá-lo deverá receber, como parâmetro, 
um elemento, também, float. Como é um método que não terá retorno, então, 
utiliza-se o tipo de retorno como void. Além disso, o padrão para métodos set-
ters é sempre utilizar a palavra “set” e, em seguida, concatenar com o nome da 
variável. No caso em tela, teríamos o método de nome setSaldo, que terá a sua 
implementação da seguinte forma:
//metodo setSaldo – setter para o atributo saldo
public void setSaldo(float s){
 this.saldo = s;
}
//metodo setNumConta – setter para o atributo numConta
public void setNumConta(int n){
 this.numConta = n;
}
U
N
IC
E
S
U
M
A
R
57
Além do método de alterar o valor do atributo, precisamos utilizar o método 
para “resgatar” o valor deste atributo, a esses métodos chamamos de getters e a 
característica deste tipo de método é que ele retorna o valor do atributo para o 
elemento que o chama. Os métodos “get” são precedidos pela palavra “get” e o 
nome do atributo, e eles devem retornar elementos do mesmo tipo de atributo em 
questão. Utilizando o mesmo exemplo do atributo Saldo e o atributo numConta, 
teremos os métodos getters a seguir:
//metodo getSaldo – getter para o atributo saldo
public float getSaldo(){
 return this.saldo;
}
//metodo getNumConta – getter para o atributo numConta
public int getNumConta(){
 return this.numConta;
}
Como exemplo, a conta foi reimplementada e, utilizando os métodos getters e 
setters de maneira adequada, ela ficará como apresentado no código a seguir. Note 
que, para o atributo saldo, a implementação do getter e do setter não foi feita,tendo em vista que existem três operações básicas que devem, em um ambiente 
de caixa eletrônico, “controlar” essa variável. Essas operações são: sacar, transferir 
ou depositar, que serão implementadas posteriormente.
U
N
ID
A
D
E
 2
58
package conta;
import cliente.Pessoa;
public class Conta {
 private float saldo;
 private Pessoa titular;
 private int numConta;
 private int tipoConta;
 public int getNumConta() {
 return numConta;
 }
 public void setNumConta(int numConta) {
 this.numConta = numConta;
 }
 public int getTipoConta() {
 return tipoConta;
 }
 public void setTipoConta(int tipoConta) {
 this.tipoConta = tipoConta;
 }
 public Pessoa getTitular() {
 return titular;
 }
 public void setTitular(Pessoa titular) {
 this.titular = titular;
 }
}
Dica da ferramenta: no Netbeans, é possível a criação “automática” dos métodos getters e 
setters. Para isto, no código-fonte de sua classe, após a declaração dos atributos, pressio-
ne a tecla Alt+Insert e escolha a opção “getters e setters...” e, então, selecione os atributos 
que deseja gerar os métodos. 
Fonte: os autores.
pensando juntos
U
N
IC
E
S
U
M
A
R
59
4 
MODIFICADORES 
STATIC, ABSTRACT 
e Final
Além dos modificadores de acesso, o Java permite a utilização de outros modifi-
cadores, são eles: static, final e abstract. Cada um deles será abordado em seções, 
pois eles têm características bem diferentes entre si.
Modificador static
O modificador static pode ser aplicado a variáveis e a métodos, e a principal 
característica dele é que, se tratando de atributos, todos os objetos compartilham 
do mesmo espaço de memória e, tratando-se de método, este pode ser acessado 
sem a necessidade de instância do objeto.
Você, provavelmente, já criou alguma aplicação em Java e se deparou com o méto-
do “public static void main (String args[])”, e deve ter se perguntado: “o que significam 
todas estas palavras antes do nome do método principal?”. Então, vamos por partes. 
O modificador de acesso public indica que este método pode ser visualizado 
de qualquer classe do projeto, o modificador static indica que, para acessar o 
método da classe, não é necessário instanciá-lo, e o que acontece é que métodos 
U
N
ID
A
D
E
 2
60
e variáveis static são alocados em memória antes que qualquer objeto seja criado. 
Por essa razão, um atributo não static, originário de uma classe ausente no mé-
todo static, não pode ser acessado de forma direta, pois ele só existirá a partir da 
instância do objeto. Por exemplo, no código a seguir, da classe “Exemplo”, temos 
duas variáveis: valor (int) e valor2(static int). Note que, dentro do método static 
(public static void main(String[] args)), ao tentar atribuir um inteiro 30 à variável 
valor, o NetBeans acusará o erro com os seguintes dizeres: “non-static variable 
valor cannot be referenced form a static context”, traduzindo, isto significa que 
a variável static valor não pode ser referenciada em um contexto static.
package exemplo;
public class Exemplo {
 int valor;
 static int valor2;
 public static void main(String[] args) {
 valor = 30;
 valor2 = 10;
 } 
}
Para resolver esse erro, temos duas saídas: uma é transformar o atributo valor em 
static, a outra é criar um objeto (instância) do tipo “Exemplo” e, então, acessar e 
modificar a variável valor. Veja, a seguir, como ficariam as duas soluções.
package exemplo;
public class Exemplo {
 static int valor;
 static int valor2;
 public static void main(String[] args) {
 valor = 30;
 valor2 = 10;
 } 
}
U
N
IC
E
S
U
M
A
R
61
package exemplo;
public class Exemplo {
 int valor;
 static int valor2;
 public static void main(String[] args) {
 Exemplo e = new Exemplo();
 e.valor = 30;
 valor2 = 10;
 } 
}
Uma variável estática é compartilhada por todas as instâncias de uma classe, ou 
seja, em vez de cada instância da classe ter uma cópia dessa variável, esta é, apenas, 
uma, compartilhada por todas as instâncias. Para a existência de uma variável 
estática, sequer é necessária a criação de uma instância da classe que tenha a va-
riável, é necessário, somente, que a classe seja carregada na Máquina Virtual Java, 
já que esta é criada e inicializada no momento de carga da classe.
Exemplificando, imagine que haja um limite para realizar transferências entre 
contas e que esse limite seja igual para todas as contas. Para resolver este proble-
ma, basta declarar o atributo (limiteTransferencia) como static; dessa forma, o 
limite é alterado para todas as referências de conta. Veja a Figura 8, a seguir, em 
que é ilustrada a variável (limiteTransferencia) como um atributo compartilhado. 
Figura 8 - Ilustração de variável static limiteTransferencia / Fonte: os autores. 
Conta c1 Conta c2
saldo = 200,40
titular = “Joaquim”
numConta = 3540
tipoConta = 1
saldo = 400,40
titular = “Maria”
numConta = 35520
tipoConta = 1
Conta.limiteTransferencia=3000
U
N
ID
A
D
E
 2
62
Dica de programação: quando se declara um atributo do tipo final, usa-se, como padrão, 
o seu nome em caixa alta, por se tratar de um atributo constante. 
pensando juntos
O modificador final
O modificador final restringe, ainda mais, o acesso aos elementos de uma classe. 
Ele faz com que o atributo não possa ser modificado em tempo de execução, ou 
seja, cria-se uma variável que terá um valor constante, do início ao término da 
execução da aplicação. Para classes, indica que estas não poderão ser herdadas 
(não poderão ter filhos) e, para métodos, indica que estes são impossibilitados 
de serem sobrescritos (usar técnicas de polimorfismo).
Variáveis de instância do tipo final podem ser declaradas em conjunto com 
o modificador static. Nesse caso, se este for declarado, na inicialização da variá-
vel, o valor atribuído a ele será o mesmo para todos os objetos e não poderá ser 
modificado durante a execução do projeto. Se uma variável static final não for 
inicializada, ocorrerá erro de compilação. Podemos, então, utilizar o exemplo do 
limite de transferência para ilustrar a utilização do modificador final. 
public class Conta{
 …
 private final static float LIMITETRANSFERENCIA=3000;
 …
}
Métodos final não podem ser sobrescritos, ou seja, eles, em uma superclasse (clas-
se pai), não podem ser reimplementados na subclasse (classe filha). Os métodos 
declarados como private são, implicitamente, final, porque não é possível sobres-
crever em uma subclasse.
Uma classe final não pode ser superclasse, ou seja, não pode ter classes que 
herdam as suas propriedades. Portanto, quando uma classe é final, implicitamen-
te, todos os métodos são final.
U
N
IC
E
S
U
M
A
R
63
O modificador abstract
O modificador abstract é aplicado, somente, a métodos e a classes. Métodos abs-
tratos não fornecem implementações e, em classes abstratas, não é possível a criação 
de objetos da classe e, normalmente, possuem um ou mais métodos abstratos.
O objetivo de criação de classes abstratas é fornecer uma superclasse apropriada 
a partir da qual outras classes podem herdar e, assim, compartilharem um design 
comum. Veja, a seguir, a criação da classe (Pessoa) como uma classe abstrata. Basea-
da no projeto do caixa eletrônico, essa classe possui, também, um método abstrato 
para cadastro. A declaração deste método “força”, nas subclasses, a programação dele.
package cliente;
public abstract class Pessoa {
 protected String telefone;
 protected String nomePessoa;
 protected Endereco e = new Endereco();
 public abstract void cadastra();
 public String getTelefone() {
 return telefone;
 }
 public void setTelefone(String telefone) {
 this.telefone = telefone;
 }
 public String getNomePessoa() {
 return nomePessoa;
 }
 public void setNomePessoa(String nomePessoa) {
 this.nomePessoa = nomePessoa;
 }
 public Endereco getE() {
 return e;
 }
 public void setE(Enderecoe) {
 this.e = e;
 }
}
U
N
ID
A
D
E
 2
64
Logo, a seguir, é apresentada a “tentativa” de criação de um objeto de uma classe 
abstrata, no detalhe da mensagem do IDE (Figura 9), em que uma classe abstrata 
não pode ser instanciada.
package caixaeletronico;
import cliente.Pessoa;
public class Caixa Eletrônico {
 public static void main(String[] args) {
 Pessoa p = new Pessoa();//erro nesta linha - Pessoa 
is abstract; cannot be instantiated
 }
}
Figura 9 - Dica de erro ao instanciar classe abstrata / Fonte: os autores. 
Criaremos uma subclasse para a classe Pessoa. Note que o método “cadastra” 
precisou ser implementado na classe Física.
package cliente;
import java.util.Scanner;
public class Fisica extends Pessoa {
 private String cpf;
 //implementação do método abstrato é imprescindível
 @Override
 public void cadastra(){
 //leitura via teclado
 Scanner tec = new Scanner(System.in);
 System.out.println("Digite o nome ”);
 nomePessoa = tec.nextLine();
 System.out.println("Digite o telefone");
 telefone = tec.nextLine();
 System.out.println("Digite o cpf");
 cpf = tec.nextLine(); 
Pessoa is abstract; cannot be instantiated
----
(Alt-Enter mostra dicas)
"
U
N
IC
E
S
U
M
A
R
65
Muitos devem se perguntar para que serve esta anotação. Quando criamos uma sobre-
posição, costumamos utilizar a anotação @Override, que identifica que esse método está 
sendo reescrito. Quando usamos a anotação, o código, além de legível, obriga o compila-
dor a aplicar as regras de reescrita para essa marcação. 
Fonte: os autores.
explorando Ideias
O que são esses construtores? Um construtor é o primeiro “método” executado sempre 
que uma classe é instanciada. Quando se utiliza a palavra-chave new, o construtor será 
executado e inicializará o objeto. 
Fonte: os autores.
explorando Ideias
 e.cadastra();
 }
}
Um construtor não é um método, pois este não possui a declaração de retorno. Lembre-
-se, porém, disso: toda classe em Java tem, pelo menos, um construtor, exceto interfaces.
5 
CONSTRUTORES DE 
CLASSE
U
N
ID
A
D
E
 2
66
Existem classes que, quando inicializadas, requerem algum tipo de parâmetro, 
por exemplo, objetos do tipo Scanner (para realizar leitura de informações para 
o projeto), que você pode conferir no código, a seguir.
Scanner tec = new Scanner (System.in);
Quando fazemos isto, estamos inicializando a classe com os dados parâmetros. O 
construtor inicializa as variáveis de instância da classe, como também executa códigos 
necessários para a inicialização de uma classe. Em outras palavras, no construtor, você 
pode determinar o que será realizado assim que o seu objeto for instanciado.
Vamos utilizar o exemplo da Classe Pessoa e criar um construtor para ela:
public abstract class Pessoa {
 protected String telefone;
 protected String nomePessoa;
 protected Endereco e = new Endereco();
 
 public Pessoa(){
 super();
 System.out.println("Executando o construtor de 
Pessoa");
 }
 ...//outros métodos da classe
}
Note que o construtor é similar a um método, mas ele não tem nem tipo de retorno, 
nem void. Outro fato importante: um construtor sempre terá o mesmo nome da 
classe. Modificadores de acesso podem ser atribuídos aos construtores, inclusive, o 
private. Se o construtor não for criado junto ao código-fonte da classe, o com-
pilador criará, automaticamente, um construtor para a sua classe. 
Quando uma classe é instanciada, o método super() dela é chamado, mesmo 
que não seja declarado, pois, em algum momento, a classe terá que ser inicializada. 
Lembre-se que todas as classes em Java são filhas da classe Object, ou seja, Object é a 
mãe de todas as classes (ela fornece métodos como equals e toString, por exemplo).
Ainda, em nosso exemplo apresentado na Figura 8, em que objetos do tipo 
Física são filhos da classe Pessoa, quando criamos uma instância de Física, os 
U
N
IC
E
S
U
M
A
R
67
construtores são executados em forma de pilha: Física chama Pessoa, que cha-
ma Object. Ou seja, o construtor de Física será executado por último. Analise os 
códigos a seguir, logo após a saída do compilador, na Figura 10.
public class Fisica extends Pessoa{
 private String cpf; 
 public Fisica(){
 System.out.println("Pessoa Fisica");
 }
}
public class CaixaEletronico {
 public static void main(String[] args) {
 Fisica f = new Fisica();
 }
}
Figura 10 - Saída do compilador quando se instancia a classe Física / Fonte: os autores.
Note que, ao realizar a instância da classe Física, o construtor da classe Pessoa, 
também, foi acionado.
Uma classe pode possuir mais de um construtor. Você deve estar se pergun-
tando: mas como isto é possível? Para tal, é preciso criar construtores com ar-
gumentos diferentes, dessa forma, criam-se diversas formas de inicializar um 
objeto. Como exemplo, utilizaremos a classe Física, passando, como parâmetro, 
no momento da inicialização da classe, o nome do titular da conta. Analise os 
códigos a seguir e, depois, a saída do compilador, na Figura 11.
U
N
ID
A
D
E
 2
68
package cliente;
import java.util.Scanner;
public class Fisica extends Pessoa{
 private String cpf; 
 public Fisica(){
 System.out.println("Pessoa Fisica");
 }
 public Fisica(String nome){
 nomePessoa = nome;
 }
}
//...outros métodos da classe
package caixaeletronico;
import cliente.Fisica;
public class CaixaEletronico {
 public static void main(String[] args) {
 Fisica f = new Fisica();
 Fisica f2 = new Fisica("Joaquim");
 System.out.println(f2.getNomePessoa());
 }
}
Figura 11 - Saída do console / Fonte: os autores.
U
N
IC
E
S
U
M
A
R
69
Não há limite para a criação de construtores, você pode criar, em uma classe, 
quantos forem necessários, mas o que deve diferenciar os construtores são os 
parâmetros. Por exemplo, se um construtor requer uma String, então, não se pode 
criar outro construtor solicitando uma String, por mais que sejam variáveis dife-
rentes, porém, se for um construtor solicitando uma String, e outro, duas Strings, 
é possível, ou seja, o tipo e o número de parâmetros serão os determinantes para 
que o compilador saiba qual construtor deve ser chamado.
Um ponto importante é que, enquanto o construtor não for executado, ne-
nhum acesso à variável de instância ou método será possível, isto quer dizer que 
um objeto não pode ser utilizado até ser inicializado, o que é óbvio, mas, também, 
significa que você não pode tentar sabotar o construtor do objeto antes de chamar 
super(), como pode ser visto no código a seguir:
package cliente;
import java.util.Scanner;
public class Fisica extends Pessoa{
 
 private String cpf; 
 public Fisica(){
 System.out.println("Pessoa Fisica");
 }
 public Fisica(String nome){
 nomePessoa = nome;
 super(); //error
 }
}
//...outros métodos da classe
}
A chamada de super(), no construtor da classe Física, retorna um erro de compi-
lação, em que será mostrado ao programador uma mensagem de que a chamada 
ao construtor de super() deve ser, no construtor, a primeira sentença.
U
N
ID
A
D
E
 2
70
CONSIDERAÇÕES FINAIS
Nesta unidade, aprendemos os conceitos dos pilares da orientação a objetos, o 
encapsulamento. É por ele que se possibilita garantir os níveis de proteção dos 
atributos e métodos com o uso dos modificadores de acessos: public, private e 
protected. Para acessar os atributos e métodos que estão encapsulados, utilizamos 
os modificadores privados por meio dos métodos públicos getters e setters.
Além dos modificadores de acesso, aprendemos a utilizar o modificador final 
para criar constantes, métodos que não podem ser sobrescritos e classes que não 
podem ter filhos. Sendo assim, esse modificador é importante, pois ele pode ser 
utilizado para garantir a esterilidade de uma classe ou de um método.
Vimos o modo de funcionamento do modificador static, que compartilha 
o mesmoespaço de memória para atributos desse tipo e, também, como os 
métodos estáticos são alocados em memória antes da instância da classe e que 
podem ser chamados utilizando, somente, o nome da classe e do método. O es-
tático é muito utilizado para realizar validações de campos, pois nem sempre é 
necessário instanciar uma classe inteira, sendo assim, invoca, apenas, o método 
que realizar a operação necessária.
Não menos importante, aprendemos sobre o modificador abstract, que faz 
com que a classe não possa ser instanciada, e os métodos abstratos, apenas, in-
dicam o que deve ser implementado nas classes filhas. Dessa forma, temos que 
as classes abstratas servem de modelo para as demais classes que as estendem.
Por fim, vimos como funcionam os construtores em Java, assim como a 
forma de inicializar os seus objetos utilizando tais construtores. Estes podem 
ser inicializados vazios ou com valores passados por parâmetros ou por valor 
padrão. Recurso este muito utilizado quando é necessário instanciar valores 
padrões na classe, mas cuidado: esses valores devem ser essenciais para todo o 
código, caso contrário, sempre que instanciado, a classe deverá fornecer valores 
a métodos que não os utilizam.
Na próxima unidade, apresentaremos a você os conceitos que envolvem outro 
pilar da programação orientada a objetos: a herança. Este recurso fornece subsídios 
que permitem herdar características e comportamentos de classes antecessoras. 
Tal processo permite o reuso de códigos e, ao mesmo tempo, a sua personalização, 
incrementando o que é necessário, além daquilo já herdado de seu antecessor.
71
na prática
1. Os modificadores de acesso são elementos que envolvem a programação orien-
tada a objetos. A partir destes, é possível ocultar detalhes internos de uma classe, 
como atributos (variáveis) e métodos (funções) de um objeto, ou seja, aplicar o 
conceito de encapsulamento na prática. Com esses modificadores, é possível de-
terminar quais níveis de visibilidade que um atributo ou um método possui em 
relação à sua classe e às demais do projeto. Os modificadores de acesso disponí-
veis são: public, private e protected.
Sobre os modificadores de acesso no encapsulamento de atributos e métodos, 
analise as afirmações a seguir:
I - Um atributo com o modificador private permite ser acessado por um método 
público de uma classe que estende a sua classe.
II - Um atributo com o modificador public permite ser acessado diretamente por 
qualquer classe que a instancie, ou que tenha estendido de sua classe.
III - Um atributo com o modificador protected permite ser acessado por um método 
público de uma classe que não estende a sua classe.
IV - Uma forma de acessar os atributos com modificadores private e protected é imple-
mentar os métodos assessores, desde que estes estejam com visibilidade public.
Assinale a alternativa correta:
a) Apenas I está correta.
b) Apenas I e II estão corretas.
c) Apenas II e IV estão corretas.
d) Apenas I, II e IV estão corretas.
e) Apenas I, III e IV estão corretas.
72
na prática
2. Com base em nossos estudos, analise o código a seguir:
package cadpessoa;
public class Pessoa {
 private String pai;
 public String getPai() { return pai; }
 public void setPais(String pai) { this.pai = pai;}
 
 public Pessoa (String pai){
 this.setPais(pai);
 System.out.println("Meu pai é:"+this.getPai());
 }
 public static void main(String[] args) {
 ____________
 }
}
De acordo com o código anterior, assinale a alternativa que mostra a instância da 
classe no objeto pessoa1 e passe, por parâmetro, o valor "José":
a) pessoa1 = new Pessoa("José").
b) Pessoa pessoa1 = new Pessoa("José").
c) Pessoa pessoa1 = new cadPessoa("José").
d) cadPessoa pessoa1 = new Pessoa("José").
e) cadPessoa.pessoa1 = new Pessoa("José").
73
na prática
3. Analise o código fonte a seguir: 
package cadpessoa;
public class Resumo {
 public String conteudo = "Estou estudando o ";
 public String getConteudo() { return conteudo;}
 public void setConteudo(String conteudo) { this.conteudo = 
conteudo; }
 
 public static void main(String[] args) {
 Resumo obj = new Resumo();
 System.out.println(obj.getConteudo());
 obj.setConteudo("resumo de Matemática");
 System.out.println(obj.getConteudo());
 }
}
De acordo com a classe anterior, assinale a alternativa correta para a saída em tela.
a) Estou estudando o
Estou estudando o 
b) resumo de Matemática
Estou estudando o
c) resumo de Matemática
resumo de Matemática
d) Estou estudando o
resumo de Matemática
e) Estou estudando o resumo de Matemática 
74
na prática
4. Analise a imagem a seguir e identifique qual é a classe, quais são os atributos 
e os métodos. 
5. Depois que Romeu terminou o sistema de PetShop, ele percebeu que esqueceu 
de implementar um dos recursos de orientação a objetos, e este mecanismo está 
causando sérios transtornos de controle de acesso, ou seja, o mecanismo que ele 
esqueceu provê proteção de acesso aos membros internos de um objeto.
Diante do contexto anterior, cite qual foi o mecanismo que Romeu esqueceu de 
implementar e como ele poderá fazer esta implementação.
Casa
- janela : int
- porta : int
- quartos : int
+ inserir() : void
+ listar() : void
+ excluir() : void
75
aprimore-se
ORIENTAÇÃO A OBJETOS 
Inovações tecnológicas surgidas na área de Informática têm criado uma necessida-
de de utilização e manipulação de informações que antigamente não eram utiliza-
das. Os tipos de dados complexos, como os objetos, passaram a ser manipulados 
através das linguagens de programação, que passaram a receber a conotação de 
Linguagem de Programação Orientada a Objetos.
A programação estruturada, em se tratando, principalmente, de manutenção de 
sistemas, possui taxas de reutilização muito baixas, dificultando a manutenção dos 
programas anteriormente desenvolvidos. 
A orientação a objetos tem como objetivo principal modelar o mundo real, e garantir 
que as taxas de manutenibilidade (manutenção) serão maiores diante deste contexto. 
Isso é possível, pois utilizando uma linguagem de programação orientada a objetos con-
segue-se obter um desenvolvimento mais rápido, visto que este desenvolvimento ocorre 
em módulos, em blocos de códigos correspondentes aos objetos e seus acoplamentos. 
Através da orientação a objetos pode-se obter uma maior qualidade e agilidade 
no desenvolvimento, pois o fator reusabilidade (reutilização) permite que se re-uti-
lize outros objetos que foram anteriormente desenvolvidos e podem ser facilmente 
incorporados na aplicação. A reusabilidade também garante uma manuseabilidade 
melhor do programa, pois os testes referentes aos componentes, já foram previa-
mente executados, garantindo assim a utilização coesa dos objetos.
A orientação a objetos surgiu na década de 60, baseada na Teoria dos Tipos de Álgebra, mas 
somente na década de 90 começou a ser amplamente utilizada computacionalmente. Ela tem 
como princípio fundamental representar o mundo real e a forma de se interagir com os objetos. 
Mas, o que é um objeto? Atualmente, há milhares de milhares de objetos que se 
pode tocar e perceber. Agora mesmo, você está tocando em um objeto denominado 
livro e posso garantir que deste livro que você está nas mãos, somente há um exem-
plar. Há um modelo deste livro, que é responsável pela criação do mesmo em série, 
mas este livro, que está nas suas mãos, idêntico, que possui um grifo de lápis (caso 
você já tenha dado um) somente há um, este nas suas mãos. É esta a característica 
principal dos objetos, eles são únicos e somente há um único objeto no mundo. 
Fonte: Claro e Sobral (2008, p. 8).
76
eu recomendo!
Java 8 – Ensino Didático. Desenvolvimento e Implementação 
de Aplicações
Autor: Sérgio Furgeri
Editora: Érica e Saraiva
Sinopse: a Java tem se desenvolvido muito nos últimos anos, fato 
que a tem colocado entre as linguagens de programação mais 
usadas. Milhares de empresas no Brasil e no mundo têm se apri-morado e desenvolvido as mais diversas soluções. Isto tem ocasionado, cada vez 
mais, a procura por profissionais qualificados e certificados em Java. Adquirir co-
nhecimentos acerca da orientação a objetos, juntamente com a linguagem Java, 
se faz necessário a qualquer profissional da área de computação. Este livro ex-
plora as funcionalidades básicas disponíveis no Java 8, fornecendo conhecimen-
to inicial para a elaboração e o desenvolvimento de aplicações nessa linguagem, 
apresentando os aspectos fundamentais relacionados à orientação a objetos, à 
criação da interface do usuário, às aplicações com arquitetura do tipo cliente/
servidor hospedadas na internet, ao acesso a banco de dados com MySQL e à 
geração de gráficos. Aborda a estrutura básica da linguagem e os seus pacotes 
fundamentais. Possui, também, exercícios ao final de cada capítulo para a fixação 
do aprendizado, além de outros materiais de apoio.
livro
77
eu recomendo!
Nesta aula de programação orientada a objetos (POO), aprenderemos quais são 
os seus três pilares e estudaremos o primeiro deles: o encapsulamento da POO.
https://www.youtube.com/watch?v=x4JfzV0Wb5w
Veja, na série “Começando aos 40”, conhecimentos básicos para iniciantes em 
programação. 
https://www.youtube.com/watch?v=sx4hAHhO9CY
conecte-se
Java – Ensino Didático. Desenvolvimento e Implementação 
de Aplicações
Autor: Sérgio Furgeri 
Editora: Érica
Sinopse: a obra aborda os aspectos essenciais da linguagem Java, 
considerando a versão 9, o que proporciona ao leitor o entendi-
mento dos principais conceitos referentes à orientação a objetos, 
ao acesso ao banco de dados, à geração de gráficos e ao uso do Java na internet. 
Fornece noções essenciais voltadas à criação de aplicações do tipo cliente/servi-
dor com acesso ao banco de dados MySQL, usando o container Java Tomcat 9. 
Também é compatível com JShell e com NetBeans.
livro
3
HERANÇA E 
POLIMORFISMO
PLANO DE ESTUDO 
A seguir, apresentam-se as aulas que você estudará nesta unidade: • O que é herança? • Como imple-
mentar herança • O que é polimorfismo?.
OBJETIVOS DE APRENDIZAGEM 
• Entender o conceito de herança • Aplicar o conceito de herança • Entender e aplicar o conceito de 
polimorfismo.
PROFESSORES 
Dr. Edson Alves de Oliveira Junior
Me. Andre Abdala Noel
Me. Márcia Cristina Dadalto Pascutti 
Me. Rafael Alves Florindo 
Esp. Victor de Marqui Pedroso
Esp. Janaina Aparecida de Freitas
INTRODUÇÃO
Caro(a) aluno(a), estudamos os conceitos de encapsulamento, modifica-
dores de acesso e construtores, em Java, recursos estes que prezam pelo 
controle de acesso aos elementos da classe bem como o momento de par-
tida delas. Nesta terceira unidade, estudaremos os conceitos de herança, 
polimorfismo e interface. 
Primeiramente, abordaremos a herança, a qual possibilita que classes 
com características e comportamentos semelhantes possam ser implemen-
tadas de forma agrupada, ou seja, por meio de superclasses e subclasses 
(classes filhas). As subclasses são consideradas especializadas, pois terão 
tudo o que a classe pai possui, mas com suas características e seus com-
portamentos próprios. Esse recurso, além de agrupar classes semelhantes, 
visa a reaproveitar o código, uma vez que, se as classes estão herdando as 
características e os comportamentos, é como se estivéssemos reescreven-
do todos os códigos na classe filha. Contudo esta reescrita fica apenas em 
tempo de execução no momento da instância do objeto.
Ao herdar os atributos e comportamentos, os níveis de visibilidades 
são herdados também. Dessa forma, faz-se necessária a implementa-
ção dos métodos de acesso setters e getters para os modificadores de 
visibilidade private e protected.
Na sequência, abordaremos o conceito de polimorfismo, que é aplicado 
nas classes herdeiras. Esse conceito é encontrado nos métodos que contêm 
a mesma assinatura de sua classe mãe. Nesse caso, o polimorfismo permite 
que seja reutilizado parte do método da classe pai, porém este é criado com 
comportamentos distintos, de acordo com a origem do objeto. 
Para mostrar a você como utilizar esses recursos, abordaremos alguns 
exemplos que empregam as técnicas de herança e polimorfismo. Um será 
o exemplo discutido durante a apresentação do tema, e o outro mostrará 
um projeto complementar desenvolvido com as técnicas citadas.
U
N
ID
A
D
E
 3
80
1 
O QUE É 
HERANÇA?
Começaremos a nossa unidade mostrando uma perspectiva do mundo real. 
Imagine um peixe, como na Figura 1, a seguir. Qualquer espécie animal possui 
características próprias que definem, com precisão, em qual espécie o animal se 
enquadra. Utilizaremos como exemplo os peixes: eles possuem brânquias (para 
respirar), barbatana/nadadeira para a locomoção e boca para a alimentação.
De maneira geral, todos os peixes possuem essas características, agora, se nos 
aprofundarmos no mundo dos peixes e analisarmos as características de cada 
espécie, como: tipo de escama, tamanho e coloração do animal, se ele é de água 
doce ou salgada, número de dentes, entre outras características, teremos uma 
infinidade de espécies que se diferem, como o peixe-palhaço, que possui carac-
terísticas específicas à sua raça. Por exemplo, o tamanho reduzido, a coloração 
alaranjada, as manchas brancas e pretas distribuídas pelo seu corpo.
Um filhote de peixe-palhaço possui as mesmas características de seus pais, 
avós, bisavós e outras gerações, ou seja, ele herda todas as características da raça 
e, além disso, ele possui todas as características comuns a qualquer peixe.
U
N
IC
E
S
U
M
A
R
81
Figura 1 - Peixe-palhaço
Mantendo o raciocínio, podemos dizer que um peixe-palhaço é uma raça da 
espécie peixe; se fôssemos transformar esse conceito na programação orientada a 
objetos, basta transformar o peixe-palhaço em uma classe de nome PeixePalhaco, 
e ela herdaria as características dos Peixes, representada pela classe Peixe.
Dessa forma, podemos afirmar que o PeixePalhaco é uma subclasse da su-
perclasse Peixe. Em outras palavras, objetos do tipo PeixePalhaco terão todas as 
características de objetos do tipo Peixe, porém terão algumas especificidades que 
os diferem de outros tipos de peixe. Veja, na Figura 2, o esquema de herança que 
ilustra o caso em tela.
Figura 2 - Superclasse Peixe e respectivas subclasses / Fonte: os autores.
PeixePalhaco
- numeroListras : int
PeixeBagre Tucunare Pacu
Peixe
- tipoPele: String
- numDentes : int
+ nadar() : void
+ comer() : void
U
N
ID
A
D
E
 3
82
Todas as espécies de peixes, ilustradas na Figura 2, herdam todos os atributos 
e métodos da classe Peixe, ou seja, herdam as suas características e os seus 
comportamentos se houver, e é este o papel da herança na orientação a objetos. 
De maneira geral, a herança permite a criação de novas classes (subclasses) a 
partir daquelas já existentes (superclasses), “herdando” características existentes 
na classe a ser estendida. Essa técnica implica em grande reaproveitamento 
de código existente, uma vez que não há a necessidade de reimplementarão 
de métodos já criados nas superclasses. Como você pode notar, criamos um 
projeto e, nele, criamos as classes a seguir:
Em relação a superclasses e 
subclasses, podemos dizer que as 
segundas são especializações das 
primeiras que, por sua vez, são ge-
neralizações de subclasses. Em ou-
tras palavras, subclasses são mais 
especializadas do que as suas su-
perclasses, as quais são mais gené-
ricas. As subclasses herdam todas as 
características de suas superclasses, 
como suas variáveis, seus métodos 
e suas visibilidades.
A linguagem Java permite o uso de herança simples, mas não permite a imple-
mentação de herança múltipla, o que significa que uma classe pode herdar mé-
todos e atributos de mais de uma classe. Para superar essa limitação, o Java faz 
uso de interfaces, conteúdo que estudaremos na Unidade 4.
Em Java, a palavra que define que uma classe herda as característicasde outra 
é extends, e ela deve ser utilizada assim que a classe for criada. Veja, nos códigos 
a seguir, um exemplo que mostra onde deve ser empregada a palavra extends.
package peixes;
public class Peixe {
 //atributos
 private String tipoPele;
 private int numDentes;
 //métodos
Figura 3 - Herança / Fonte: os autores.
U
N
IC
E
S
U
M
A
R
83
 public void nadar(){
 System.out.println("Mecher as barbatanas");
 }
 public void comer(){
 System.out.println("Procurar comida e comer");
 }
 public String getTipoPele() {
 return tipoPele;
 }
 public void setTipoPele(String tipoPele) {
 this.tipoPele = tipoPele;
 }
 public int getNumDentes() {
 return numDentes;
 }
 public void setNumDentes(int numDentes) {
 this.numDentes = numDentes;
 } 
}
package peixes;
public class PeixePalhaco extends Peixe {
 //implementação da classe peixe palhaco
 private int numeroListras;
 public int getNumeroListras() {
 return numeroListras;
 }
 public void setNumeroListras(int numeroListras) {
 this.numeroListras = numeroListras;
 }
}
U
N
ID
A
D
E
 3
84
Da forma como foram implementados esses códigos, a classe PeixePalhaco herda 
todos os atributos e métodos da classe Peixe, mas com a diferença de possuir um 
atributo a mais, numeroListras, que é uma especificidade do peixe-palhaço em 
relação a outros tipos de sua espécie.
Ainda utilizando dois últimos códigos, elaboraremos, agora, uma classe prin-
cipal que cria uma instância de peixe-palhaço em peixe1 e chama/invoca os seus 
métodos nadar() e comer().
package peixes;
public class Principal {
 public static void main(String[] args) {
 PeixePalhaco peixe1 = new PeixePalhaco();
 peixe1.nadar();
 peixe1.comer();
 } 
}
No código a seguir, será produzido, no compilador, uma saída:
Mexer barbatanas
Procurar comida e comer
Note que os métodos nadar() e comer() não foram implementados na classe 
PeixePalhaco, somente na classe Peixe. Pelo fato de PeixePalhaco ser uma sub-
classe de Peixe, os métodos da classe serão herdados, automaticamente, por 
objetos do tipo PeixePalhaco.
U
N
IC
E
S
U
M
A
R
85
2 
COMO IMPLEMENTAR 
HERANÇA
Agora que você já entendeu o conceito-base para herança, analisaremos a Figura 
4, a seguir, que ilustra o projeto como um todo a partir de um diagrama de classes:
Figura 4 - Projeto de caixa eletrônico / Fonte: os autores.
Pessoa
# nomePessoa : String
# endereco : Endereco
# telefone : String
Fisica
- cpf : String
Juridica
- cnpj : String
Juridica
- saldo : float
- numConta : int
- titular : Pessoa
- tipoConta : int
Endereco
- rua : String
- numero : int
- cidade : String
- uf : String
Caixa Eletronico
- c : Conta
- contasCadastradas : ArrayList<Conta>
+ sacar(valorSaque : float) : void
+ depositar(valorDep: float) : void
+ verificarSaldo() : void
+ transferir(numContaDestino : Conta, valor : float) : void
U
N
ID
A
D
E
 3
86
Baseando-se no problema de que, em um banco, existem dois tipos de pessoas: 
física e jurídica, podemos projetar os nossos objetos como a classe Pessoa, a qual 
seria a superclasse, e as classes Pessoa Física e Pessoa Jurídica como subclasses. 
Além disso, podemos criar a classe Pessoa como abstrata, já que este nome não 
se refere a ninguém especificamente, só de forma genérica. Sendo assim, teremos 
os seguintes códigos para cada classe Pessoa:
package cliente;
import java.util.Scanner;
public abstract class Pessoa {
 protected String telefone;
 protected String nomePessoa;
 protected Endereco e = new Endereco();
 
 public void cadastra(){
 Scanner tec = new Scanner(System.in);
 System.out.println("Digite o nome");
 nomePessoa = tec.nextLine();
 System.out.println("Digite o telefone");
 telefone = tec.nextLine();
 e.cadastra();
 }
 public String getTelefone() {
 return telefone;
 }
 public void setTelefone(String telefone) {
 this.telefone = telefone;
 }
 public String getNomePessoa() {
 return nomePessoa;
 }
 public void setNomePessoa(String nomePessoa) {
 this.nomePessoa = nomePessoa;
U
N
IC
E
S
U
M
A
R
87
 }
 public Endereco getE() {
 return e;
 }
 public void setE(Endereco e) {
 this.e = e;
 }
} 
Para a classe Física, temos:
package cliente;
import java.util.Scanner;
public class Fisica extends Pessoa {
 private String cpf;
//sobrescrita do método cadastra
 @Override
 public void cadastra(){
 Scanner tec = new Scanner(System.in);
 System.out.println("--- Cadastro de Pessoa 
Física ---");
 super.cadastra();
 System.out.println("Digite o cpf");
 cpf = tec.nextLine();
 }
 public String getCpf() {
 return cpf;
 }
 public void setCpf(String cpf) {
 this.cpf = cpf;
 }
}
U
N
ID
A
D
E
 3
88
Para a classe Jurídica, teremos:
package cliente;
import java.util.Scanner;
public class Juridica extends Pessoa{
 private String cnpj;
 //sobrescrita do método cadastra
 @Override
 public void cadastra(){
 Scanner tec = new Scanner(System.in);
 System.out.println("--- Cadastro de Pessoa 
Jurídica ---");
 super.cadastra();
 System.out.println("Digite o cnpj");
 cnpj = tec.nextLine();
 }
 public String getCnpj() {
 return cnpj;
 }
 public void setCnpj(String cnpj) {
 this.cnpj = cnpj;
 } 
}
Para a classe Endereço, teremos:
package cliente;
import java.util.Scanner;
public class Endereco {
 private String rua;
 private int numero;
 private String cidade;
 private String uf;
U
N
IC
E
S
U
M
A
R
89
 public void cadastra(){
 Scanner tec = new Scanner(System.in);
 System.out.println("--- Cadastro do Endereço ---");
 System.out.println("Digite o nome da rua");
 rua = tec.nextLine();
 System.out.println("Digite o número do estabeleci-
mento");
 numero = Integer.parseInt(tec.nextLine());
 System.out.println("Digite o nome da cidade");
 cidade = tec.nextLine();
 System.out.println("Digite o nome da Sigla do Es-
tado");
 uf = tec.nextLine();
 }
//implementar os métodos setters e getters
}
Segue a classe Conta:
package conta;
import cliente.Pessoa;
import java.util.Scanner;
public class Conta{
 private double saldo;
 private int numConta;
 private Pessoa titular = new Pessoa();
 private int tipoConta;
 
 public Conta() {
 this.setSaldo(0.0);
 }
 public double getSaldo() {
 return saldo;
U
N
ID
A
D
E
 3
90
 }
 public void setSaldo(double saldo) {
 this.saldo = saldo;
 }
 public int getNumConta() {
 return numConta;
 }
 public void setNumConta(int numConta) {
 this.numConta = numConta;
 }
 public int getTipoConta() {
 return tipoConta;
 }
 public void setTipoConta(int tipoConta) {
 this.tipoConta = tipoConta;
 }
 public Pessoa getTitular() {
 return titular;
 }
 public void setTitular(Pessoa titular) {
 this.titular = titular;
 }
 public void cadastra(){
 Scanner tec = new Scanner(System.in);
 System.out.println("Digite o número da conta");
 numConta = Integer.parseInt(tec.nextLine());
U
N
IC
E
S
U
M
A
R
91
Lembrando um pouco a teoria dos modificadores, temos que os atributos da classe Pes-
soa estão indicados com o modificador de acesso protected, e isto significa que as classes 
filhas de Pessoa terão acesso a esses atributos de forma direta. 
Fonte: os autores.
explorando Ideias
 System.out.println("Tipo da conta: [1 - Conta 
Corrente][2 - Conta Poupanca]");
 tipoConta = Integer.parseInt(tec.nextLine());
 System.out.println("Dados da Pessoa");
 titular.cadastra();
 }
 public void imprimeC(){
 System.out.println("Número da Conta: "+get-
NumConta());
 if(getTipoConta()==1){
 System.out.println("Tipo de conta: Conta 
Corrente");}else if(getTipoConta()==2){
 System.out.println("Tipo de conta: Conta 
Poupança"); 
 }
 titular.imprime();
 }
}
Note que, no momento de declaração das classes Física e Jurídica, existe a palavra 
reservada extends, e é ela que indica se uma classe é ou não subclasse de outra. 
Dessa forma, temos que as classes Física e Jurídica são filhas da classe Pessoa e, 
neste momento, todos os atributos e métodos implementados em Pessoa, auto-
maticamente, farão parte das classes filhas. 
U
N
ID
A
D
E
 3
92
Volte no código da classe Pessoa e confira quais são os atributos e métodos dessa 
classe. Feito isto, você já sabe quais são os atributos que a classe Física possui: te-
lefone, nomePessoa, endereço e CPF. Assim como os atributos da classe Jurídica: 
telefone, nomePessoa, endereço e CNPJ. Além dos atributos, as classes, também, 
possuem os métodos implementados na classe Pessoa. O código, a seguir, mostra 
quais são os métodos e atributos visíveis dentro da classe Física.
Agora, preste atenção ao código a seguir, quando precisamos “chamar” al-
gum método que faz parte da superclasse Pessoa. Note que é necessário utilizar 
a palavra reservada super, que nos dá acesso aos métodos e atributos da classe 
pai. Além disso, quando criarmos uma instância de Física, podemos, também, 
ter acesso a todos os métodos da classe Pessoa, como pode ser visto no código 
a seguir (note que os métodos getters e setters da classe Pessoa têm visibilidade 
pública por meio da classe Física, que, também, é uma classe Pessoa).
package caixaeletronico;
import cliente.Fisica;
public class CaixaEletronico { 
 public static void main(String[] args) {
 Fisica f = new Fisica();
 f.cadastra();
 System.out.println(f.getNomePessoa());
 }
}
O mecanismo de herança nos fornece um benefício notável no desenvolvimento 
de aplicações. Ao concentrarmos características comuns em uma classe e derivar-
mos as classes mais específicas a partir dela, nós estamos preparados para a adição 
de novas funcionalidades ao sistema. Se mais adiante, uma nova propriedade 
comum tiver que ser adicionada, não precisaremos efetuar alterações em todas 
as classes. Basta alterar a superclasse e todas as outras classes derivadas serão, 
automaticamente, atualizadas.
U
N
IC
E
S
U
M
A
R
93
3 
O QUE É 
POLIMORFISMO?
Em Java, o conceito de polimorfismo se manifesta apenas nas chamadas dos métodos. 
A possibilidade de polimorfismo se dá pelo fato de que métodos podem ser sobrescritos 
pelas subclasses (métodos com o mesmo nome e números de argumentos), ou seja, se o 
método da superclasse não é suficiente ou não se aplica à classe filha, ele pode ser escrito 
novamente, tendo comportamento completamente diferente ao da superclasse. 
Fonte: os autores.
conceituando
Polimorfismo significa várias (“poli”) formas (“morfo”). Em orientação a objetos, 
polimorfismo é a capacidade pela qual duas ou mais classes derivadas da mesma 
superclasse podem invocar métodos que têm a mesma identificação e assinatura 
(o mesmo nome de método), mas que possuem comportamentos distintos (de 
acordo com a forma de implementação em cada subclasse). 
O interpretador Java se encarrega de chamar, corretamente, o método a ser execu-
tado em tempo de execução. Existe, ainda, um mecanismo de sobrecarga em que 
dois métodos de uma classe podem ter o mesmo nome, porém com assinaturas 
diferentes (tipos de retorno ou tipos de argumentos diferentes), entretanto, essa 
sobrecarga não recebe o nome de polimorfismo.
U
N
ID
A
D
E
 3
94
Como dito anteriormente, tal situação não gera conflito, pois o compilador é 
capaz de detectar qual método deve ser escolhido a partir da análise dos tipos dos 
argumentos do método. Nesse caso, diz-se que ocorre a ligação prematura para o 
método correto. Em Java, todas as determinações de métodos a executar ocorrem 
por meio da ligação tardia (ocorrência em tempo de execução), exceto em dois casos: 
métodos final, que não podem ser redefinidos, e private, que, também, não podem ser 
redefinidos e, portanto, possuem as mesmas características de métodos final.
Para que o polimorfismo seja implementado de maneira correta, é necessário 
que os métodos tenham exatamente a mesma identificação (assinatura), sendo 
utilizado o mecanismo de redefinição de métodos, que é o mesmo de sobrescrita 
(@Override) de métodos em classes derivadas. A redefinição ocorre quando um 
método, cuja assinatura já tenha sido especificada, recebe nova definição, ou seja, 
um novo corpo em uma classe derivada.
 É importante observar que, quando o polimorfismo é utilizado, o comporta-
mento que será adotado por um método será definido apenas durante a execu-
ção. Embora, em geral, este seja um mecanismo que facilita o desenvolvimento 
e a compreensão do código orientado a objetos, há algumas situações em que o 
resultado da execução pode ser não intuitivo. 
Para ilustrar todo este processo, verificaremos o método cadastra, que está 
presente nas três classes do nosso exemplo (Pessoa, Física e Jurídica), e acrescen-
tar, nessas classes, a implementação do método imprime. O código, a seguir, indica 
a classe abstrata Pessoa, que possui atributos protegidos (podem ser visualizados 
por seus herdeiros) e métodos de cadastra() e imprime() implementados.
package cliente;
import java.util.Scanner;
public abstract class Pessoa {
 protected String telefone;
 protected String nomePessoa;
 protected Endereco e = new Endereco();
 
 public void cadastra(){
 Scanner tec = new Scanner(System.in);
 System.out.println("Digite o nome");
 nomePessoa = tec.nextLine();
 System.out.println("Digite o telefone");
U
N
IC
E
S
U
M
A
R
95
 telefone = tec.nextLine();
 e.cadastra();
 }
 public void imprime(){
 System.out.println("Nome: "+getNomePessoa());
 System.out.println("Telefone: "+getTelefone());
 }
//métodos setters e getters
}
No código a seguir, temos a implementação da subclasse Física, que conta com 
a implementação do método cadastra() e imprime(). Note que, antes da assina-
tura dos métodos, existe uma anotação (@Override) indicando que o método 
está sobrescrevendo outro. Caso haja a necessidade de utilização do método da 
superclasse, é necessário invocá-lo como acontece na linha “super.cadastra()”. 
Dessa forma, o método da classe Pai, também, será executado.
package cliente;
import java.util.Scanner;
public class Fisica extends Pessoa {
 private String cpf;
 //sobrescrita do método cadastra e imprime
 @Override
 public void cadastra(){
 Scanner tec = new Scanner(System.in);
 System.out.println("--- Cadastro de Pessoa 
Física ---");
 super.cadastra();
 System.out.println("Digite o cpf");
 cpf = tec.nextLine();
 }
 @Override
 public void imprime(){
 System.out.println("Pessoa Física!");
 super.imprime();
U
N
ID
A
D
E
 3
96
 System.out.println("Nome: "+getCpf());
 }
//métodos setters e getters
}
A implementação da classe Jurídica é análoga à implementação da classe Física, 
a diferença são as mensagens que serão apresentadas ao usuário do aplicativo e 
o atributo CNPJ, existente somente na classe Jurídica. O código, a seguir, mostra 
a implementação da classe Jurídica.
package cliente;
import java.util.Scanner;
public class Juridica extends Pessoa{
 private String cnpj;
 //sobrescrita do método cadastra e imprime
 @Override
 public void cadastra(){
 Scanner tec = new Scanner(System.in);
 System.out.println("--- Cadastro de Pessoa 
Jurídica ---");
 super.cadastra();
 System.out.println("Digite o cnpj");
 cnpj = tec.nextLine();
 }
 @Override
 public void imprime(){
 System.out.println("Pessoa Física!");
 super.imprime();
 System.out.println("Nome: "+getCnpj());
 }
//métodos setters e getters
}
Após implementarmos as classes filhas (Física e Jurídica) e os métodos sobrescri-
tos (cadastra() e imprime()),desenvolveremos,no método principal do projeto, 
no qual se encontra na classe CaixaEletronico, que está no pacote caixaeletronico, 
U
N
IC
E
S
U
M
A
R
97
um menu de opções. O objetivo do desenvolvimento desse menu é possibilitar a 
manipulação dos objetos do tipo Pessoa, oferecendo a opção para que o usuário 
do aplicativo selecione qual o tipo de Pessoa que deseja cadastrar. 
O menu funcionará da seguinte forma:
1. Caso escolha a opção 1, será criado um objeto do tipo Física dentro 
do vetor de Pessoas.
2. Caso a opção escolhida seja o item 2, um objeto do tipo Jurídica será criado. 
3. Caso o usuário queira imprimir os elementos cadastrados até então, ele 
pode selecionar a opção número 3. 
Note que o método cadastra do é chamado, apenas, uma vez, isto é possível por-
que as subclasses sobrescrevem um método da superclasse e, assim, esse método 
pode ter comportamentos diferentes de acordo com o objeto de origem, ou seja, 
isto é o polimorfismo! Confira, a seguir, a implementação deste código:
package caixaeletronico;
import cliente.Fisica;
import cliente.Juridica;
import cliente.Pessoa;
import java.util.Scanner;
public class CaixaEletronico {
 static Pessoa p[] = new Pessoa[10];
 public static int ultimo = 0;
 
 public static void main(String[] args) {
 Scanner tec = new Scanner(System.in);
 int opcao = 0 ;
 while(opcao!=4){
 System.out.println("Digite: ");
 System.out.println("1 - Cadastrar Pessoa Física");
 System.out.println("2 - Cadastrar Pessoa Jurídica");
 System.out.println("3 - Imprimir Clientes");
 System.out.println("4 - Sair");
U
N
ID
A
D
E
 3
98
 opcao = tec.nextInt();
 tec.nextLine();
 switch(opcao){
 case 1:
 p[ultimo] = new Fisica();
 break;
 case 2:
 p[ultimo] = new Juridica();
 break;
 case 3:
 imprimeP();
 break;
 case 4:
 System.out.println("Sair...");
 break;
 default:
 System.out.println("Valor inválido");
 break;
 }
 if(opcao==1 || opcao ==2){
 p[ultimo].cadastra();
 ultimo++;
 } 
 } 
 }
}
Outra aplicação do polimorfismo, ainda no exemplo em questão, é com o método 
de impressão, como todas as classes filhas, que, também, sobrescrevem o méto-
do imprime da superclasse. Este método pode ser chamado e se comportará de 
acordo com o objeto de origem. 
Mas se não houver sobrescrita do método? Como o compilador se compor-
ta? Nestes casos, ele invoca o método da classe Pai e executa-o. Veja, no código 
a seguir, a implementação do método de impressão. Note que não é necessário 
verificar qual tipo de Pessoa que precisa ser impressa, em tempo de execução, isto 
é resolvido. Coloque este método antes do método main();
U
N
IC
E
S
U
M
A
R
99
public static void imprimeP(){
 for(int i = 0; i < ultimo; i++){
 p[i].imprime();
 }
}
Estudo de Caso – Animais
A seguir, mostraremos um projeto que implementa herança e polimorfismo e, 
dessa forma, ilustrará os conceitos aprendidos até aqui.
Os animais do zoológico da cidade de São Paulo precisam ser catalogados 
pela idade e pelo nome. O zoológico precisa que, além disso, sejam catalogadas 
as formas de locomoção dos animais, assim como o som que eles emitem, pois a 
ideia é transformar este software em algum elemento que mostre aos visitantes 
algumas curiosidades sobre os seres que ali vivem. Para isso, a administração do 
zoológico chamou Oswaldo, um programador Java, para desenvolver um soft-
ware que auxiliasse nesta catalogação.
Oswaldo, então, 
começou a fazer a 
análise dos requisi-
tos e percebeu que se 
tratava de um caso 
em que a utilização 
de técnicas de poli-
morfismo e herança 
era imprescindível 
para que o projeto 
pudesse ser expan-
dido mais tarde, além 
de auxiliar no proces-
so de manutenção. 
Dessa forma, Oswaldo criou uma classe abstrata chamada “Animal”, e nela colocou 
as informações principais solicitadas pelo zoológico, para a catalogação. Confira a 
modelagem na Figura 5, a seguir:
No código a seguir, a classe Animal foi criada como uma classe abstrata, pois “Animal” 
é uma abordagem geral e precisa ser especificada. Essa classe possui dois atributos: nome 
Figura 5 - Exemplo de catalogação / Fonte: os autores.
U
N
ID
A
D
E
 3
100
e idade do animal, além dos métodos abstratos seLocomove() e emiteSom(), que deverão, 
obrigatoriamente, serem implementados nas classes que herdarem a classe Animal.
package animal;
abstract public class Animal {
 private String nome;
 private int idade;
 
 abstract public void seLocomove();
 abstract public void emiteSom();
 public String getNome() {
 return nome;
 }
 public void setNome(String nome) {
 this.nome = nome;
 }
 public int getIdade() {
 return idade;
 }
 public void setIdade(int idade) {
 this.idade = idade;
 } 
}
Então, Oswaldo criou as classes Cachorro, Cavalo e Preguiça, que herdam 
as propriedades de Animal e implementam os métodos abstratos. A seguir, 
apresentaremos os métodos desenvolvidos pelo programador para resolver 
esta necessidade do zoológico.
A Classe Cachorro herda todos os atributos e métodos da classe Animal e é 
obrigada a implementar os métodos seLocomove() e emiteSom(). Note, ainda, 
que a classe cachorro possui um construtor que recebe, como parâmetro, o nome 
e a idade do Animal. O código a seguir ilustra a criação dessa classe.
package animal;
public class Cachorro extends Animal {
 public void Cachorro(String nome, int idade){
U
N
IC
E
S
U
M
A
R
101
 super.setNome(nome);
 super.setIdade(idade);
 }
 @Override
 public void seLocomove(){
 System.out.println("Cachorro: "+super.getNome());
 System.out.println("Idade: "+super.getIdade());
 System.out.println("Cachorro correndo, com suas 4 patas");
 }
 @Override
 public void emiteSom(){
 System.out.println("Au Au !");
 }
}
A classe Cavalo, assim como a classe Cachorro, herda todos os atributos e métodos 
da classe Animal, além de ser obrigada a implementar os métodos seLocomove() e 
emiteSom(), porém a implementação difere da classe Cachorro, o que resulta em com-
portamento diferente, isto é o polimorfismo dos métodos seLocomove() e emiteSom().
package animal;
public class Cavalo extends Animal{
 public void Cavalo(String nome, int idade){
 super.setNome(nome);
 super.setIdade(idade);
 }
 @Override
 public void seLocomove(){
 System.out.println("Cavalo: "+super.getNome());
 System.out.println("Idade: "+super.getIdade());
 System.out.println("Cavalga, Marcha, Trota");
 }
 @Override
 public void emiteSom(){
 System.out.println("Nhiiiiiiiiii ri ri rin !");
 }
}
U
N
ID
A
D
E
 3
102
Por fim, temos, a seguir, a implementação da classe Preguiça de acordo com os 
padrões de implementação dos outros animais.
package animal;
public class Preguica extends Animal {
 public void Preguica(String nome, int idade){
 super.setNome(nome);
 super.setIdade(idade);
 }
 @Override
 public void seLocomove(){
 System.out.println("Bicho Preguiça: "+super.getNome());
 System.out.println("Idade: "+super.getIdade());
 System.out.println("Subindo na Árvore");
 }
 @Override
 public void emiteSom(){
 System.out.println("GRRRRRRRrrrrrr");
 }
}
A seguir, temos a implementação da classe principal que cria e manipula o vetor 
de Animais. Note que, no código de criação do vetor, criam-se ponteiros para 
cada Animal, mas, ainda, não se sabe qual animal será colocado em cada posi-
ção. Quem determinará o tipo do animal é o usuário, de acordo com a ordem de 
inserção por meio do método cadastraAnimal().
Este método questiona o usuário sobre qual tipo de animal será armazenado,sendo que o método fica encarregado de criar o objeto do animal desejado. Depois 
de cadastrado, é possível verificar qual animal ocupa cada posição do vetor, por meio 
do método imprimeAnimais(). Veja que cada objeto sabe exatamente como deve ser 
o seu comportamento ao chamar os métodos de seLocomove() e emiteSom().
package animal;
import java.util.Scanner;
public class AnimalPrincipal{
 Animal vetAni[] = new Animal[30];
U
N
IC
E
S
U
M
A
R
103
 static int tam=0;
 
 public static void main(String[] args) {
 int opcao=0;
 Scanner scan = new Scanner(System.in);
 AnimalPrincipal ap = new AnimalPrincipal();
 while(opcao!=3){
 System.out.println("Digite a opcao desejada:");
 System.out.println("1 - Cadastrar");
 System.out.println("2 - Listar");
 System.out.println("3 - Sair");
 
 opcao = scan.nextInt();
 scan.nextLine();
 switch(opcao){
 case 1:
 ap.cadastraAnimal(); break;
 case 2:
 ap.imprimeAnimais();break;
 case 3:
 System.out.println("Saindo.");
 break;
 default:
 System.out.println("Opção inválida");
 break;
 }
 }
 }
 public void cadastraAnimal(){
 Scanner scan = new Scanner(System.in);
 System.out.println("Digite o tipo de animal:");
 System.out.println("1 - Cachorro");
 System.out.println("2 - Cavalo");
 System.out.println("3 - Preguica");
U
N
ID
A
D
E
 3
104
 int i = scan.nextInt();
 scan.nextLine();
 if (i==1 || i==3 || i==2){
 System.out.println("Digite o nome do animal");
 String n = scan.nextLine();
 System.out.println("Digite a idade do animal");
 int id = scan.nextInt();
 scan.nextLine();
 if (i==1)
 vetAni[tam]= new Cachorro(n,id);
 else if(i==2)
 vetAni[tam]= new Cavalo(n,id);
 else if(i==3)
 vetAni[tam]= new Preguica(n,id);
 tam++;
 }
 }
 public void imprimeAnimais(){
 Scanner scan = new Scanner(System.in);
 for (int i=0;i<tam;i++){
 System.out.println("Codigo do Animal: "+i);
 vetAni[i].seLocomove();
 }
 System.out.println("Digite o código do animal que 
deseja ver");
 int cod = scan.nextInt();
 scan.nextLine();
 vetAni[cod].seLocomove();
 vetAni[cod].emiteSom();
 }
}
Execute o projeto Animal e teste as funcionalidades das técnicas de herança e 
polimorfismo aqui apresentadas.
U
N
IC
E
S
U
M
A
R
105
CONSIDERAÇÕES FINAIS
Nesta unidade, estudamos conceitos importantes para a criação de projetos 
orientados a objetos. Herança e polimorfismos que ajudam, e muito, no desen-
volvimento de aplicações que são transformadas do mundo real para o mundo 
computacional. Esses mecanismos possibilitam mais flexibilidade no projeto, 
expandindo, assim, a reutilização de códigos.
Por meio da herança, vimos que é possível herdar métodos e atributos de clas-
ses pai, e que o Java consegue identificar qual é o tipo de objeto trabalhado. Ainda 
sobre o recurso de herança, vimos que, ao aplicar a generalização, a visibilidade 
dos atributos e métodos não são alterados, ou seja, se o atributo da classe pai for 
público, ele permanece público. Dessa forma, evitamos a reescrita de códigos 
e, ainda, garantimos que os atributos e os métodos continuem protegidos pelo 
recurso de encapsulamento.
A partir da implementação da herança, é possível aplicar o recurso de poli-
morfismo, e percebemos a capacidade de sobrescrita do método, além de enten-
dermos como um método, implementado em uma superclasse e sobrescrito nas 
subclasses, pode agilizar o desenvolvimento, uma vez que não se faz necessária a 
criação de mecanismos de identificação e desvios para “chamar” o método correto.
Durante esta unidade, continuamos e desenvolvemos novos estudos de 
caso, com o objetivo de colocar em prática os conteúdos abordados no de-
correr do texto. Na próxima unidade, abordaremos os conceitos de classes 
abstratas e interfaces, recursos estes estendidos ou implementados, respecti-
vamente, nas classes do sistema. 
As classes abstratas servem como um modelo para as subclasses que a esten-
dem, obrigando ou não a implementação de alguns métodos nas classes filhas. 
Enquanto a interface serve de contrato para as classes que a implementam, obri-
gando-as a implementar os métodos da interface.
106
na prática
1. Crie uma classe chamada “Grupo” com um método imprimeDescricao() apenas im-
primindo o texto “Grupo”. Depois, crie uma classe chamada SubGrupo, herdando de 
Grupo, use o polimorfismo e reescreva o método imprimeDescricao(). Este método 
deverá imprimir o texto “Sub-Grupo”. Crie uma classe chamada Produto, herdando 
de SubGrupo, use polimorfismo e reescreva o método imprimeDescricao(). Este 
método deverá imprimir o texto “Produto”. Obs.: use a anotação @override.
2. Faça uma análise da modelagem a seguir e implemente:
3. De acordo com a modelagem do exercício anterior, instancie as classes 
Livros e Revista, de modo que imprima os dados na função mostrarGeral() 
de forma independente.
Materiais
# assunto : string
# titulo : string
+ mostrarGeral() : void
Livros
- editora : string
- edicao : int
- isbn : string
- autor : string
+ mostrarGeral() : String
Revista
- colecao : String
- editora : String
+ mostrarGeral() : String
107
na prática
4. Analise a classe a seguir. De acordo com classe Ouvidoria, implemente-a de forma 
que o usuário digite os valores de entrada e estas passem pelo método construtor 
da classe. Este deve ter implementado o toString().
5. Analise a classe a seguir. De acordo com o contexto anterior, implemente a classe 
Pagamento de forma que o usuário possa entrar com as informações dos atributos. 
É necessário que instancie a classe em um vetor de quatro posições.
Ouvidoria
- nome : String
- email : String
- assunto : String
+ Ouvidoria(nome : String, email: String, assunto : String) : void
+ toString() : void
Pagamento
- valor : double
- titulo : String
- proprietario : String
+ inserir() : void
108
aprimore-se
REVISITANDO A ORIENTAÇÃO A OBJETOS: ENCAPSULAMENTO NO JAVA
Façamos uma aposta. Tenho certeza que você, ao ver a classe abaixo, consegue 
perceber um problema nela:
class Pedido {
public String comprador;
 public double valorTotal;
 // outros atributos
}
Sim. Os atributos estão todos públicos! Isso vai exatamente contra uma das nossas 
primeiras lições quando aprendemos Java: atributos devem ser privados e precisa-
mos de getters e setters para acessá-los. Vamos então fazer essa mudança no código.
class Pedido {
 private String comprador;
 public double valorTotal;
 // outros atributos
 
 public String getComprador() { return comprador; }
 public void setComprador(String comprador) { this.comprador = 
comprador; }
 
 public double getValorTotal() { return valorTotal; }
 public void setValorTotal(double valorTotal) { this.valorTotal 
= ValorTotal; }
 
 // outros getters e setters
}
109
aprimore-se
Agora está melhor, certo? Ainda não. Deixamos escapar na verdade o grande prin-
cípio que está por trás da ideia de colocar atributos como privados. Do jeito que a 
classe Pedido está nesse momento, podemos fazer coisas como:
Pedido p = new Pedido();
// muda valor do pedido para 200 reais!
p.setValorTotal(p.getValorTotal() + 200.0);
Mas onde está o problema? Imagine outras 10 classes que fazem a mesma coisa: de 
alguma forma, elas manipulam o valor total do pedido.
Agora imagine que a regra de negócio do pedido mude: todo item comprado ganha 
desconto de 5% se o valor dele for superior a 1000 reais. Implementar essa mudan-
ça não será tarefa fácil. Precisaríamos fazê-la em diferentes classes do sistema.
Pedido
Classe 1 Classe 2 Classe 3 Classe N
todas elas manipulam valorTotal
Pedido
Classe 1
p.setValorTotal(....)
a mudança deverá ser feita em todas elas!
Classe 2
p.setValorTotal(....)
Classe 3
p.setValorTotal(....)
Classe N
p.setValorTotal(....)110
aprimore-se
Quanto tempo demoraremos para mudar o sistema? Não sabemos exatamente 
aonde devemos fazer as mudanças já que elas estão espalhadas pelo código. Esse, 
aliás, é um dos grandes problemas de códigos legados: uma simples mudança pre-
cisa ser feita em tantas classes e, na prática, sempre esquecemos algum ponto, e 
nosso sistema frequentemente quebra.
A classe Pedido não foi bem desenhada. Demos acesso direto ao atributo valor-
Total, um atributo importante da classe. Veja que o modificador private nesse caso 
não adiantou de nada, já que demos também um setter para ele. Vamos tentar dimi-
nuir o acesso ao atributo, criando métodos mais claros para a operação de depósito:
class Pedido {
 private String comprador;
 public double valorTotal;
 // outros atributos
 
 public String getComprador() { return comprador; }
 public double getValorTotal() { return valorTotal; }
 
 public void adiciona(Item item) {
if(item.getValor() < 1000) this.valorTotal += item.getValor();
 else this.valorTotal += item.getValor() * 0.95;
 }
}
Agora, para adicionarmos um item no Pedido, faremos uso desse novo comportamento:
Pedido p = new Pedido();
p.adiciona(new Item("Chuveiro Elétrico", 500.0));
Mas qual a diferença entre os dois códigos abaixo?
111
aprimore-se
Item item = new Item("Super Geladeira", 1500.0);
 
// antiga
if (item.getValor() > 1000) {
 c1.setValorTotal(c1.getValorTotal() + item.getValor() * 0.95);
}
else {
 c1.setValorTotal(c1.getValorTotal() + item.getValor());
}
 
// nova
c1.adiciona(item);
Veja que na primeira linha de código, sabemos exatamente COMO funciona a adi-
ção de um novo item no pedido: devemos pegar o valor total e somar o valor novo 
com desconto de 5% se ele for maior que 1000. Já na segunda linha de código, não 
sabemos como esse processo funciona.
Quando sabemos O QUÊ um método faz (igual ao método adiciona, sabemos 
que ele adiciona um item no pedido, por causa do nome dele), mas não sabemos 
exatamente como ele faz, dizemos que esse comportamento está encapsulado!
A partir do momento que as outras classes não sabem como a classe principal 
faz o seu trabalho, significa que as mudanças ocorrerão apenas em um lugar! Afinal, 
elas estão escondidas (encapsuladas)!
Pedido
Classe 1
p.adiciona(....)
a mudança agora acontece só no Pedido!
Classe 2
p.adiciona(....)
Classe 3
p.adiciona(....)
Classe N
p.adiciona(....)
adiciona() está
encapsulado!
112
aprimore-se
Ou seja, para implementar a regra de negócios nova, bastaria mexermos em um 
único lugar:
public void adiciona(Item item) {
 if (item.getValor() > 1000) this.valorTotal += item.getValor();
 else this.valorTotal += item.getValor() * 0.95;
 
 // nova regra de negócio aqui
}
No fim, a real utilidade do private é esconder acesso de atributos que precisam ser 
acessados de maneira mais inteligente. Mas veja que de nada adianta colocar todos 
os atributos como private e criar getters e setters para todos eles. Deixamos o en-
capsulamento “vazar” do mesmo jeito.
Esconda os atributos, mas pense em comportamentos inteligentes para acessá-
-los. Uma ótima maneira para saber se o comportamento está encapsulado é olhar 
para o código que faz uso dele! Se conseguirmos dizer o que o método faz, mas sem 
dizer como ele faz, então podemos afirmar que o comportamento está encapsulado!
Muitas vezes deixamos esses princípios passarem. Se quiser revisitar essas e ou-
tras boas práticas de Orientação a Objetos junto com os instrutores da Caelum, há 
mais posts por aqui, como um específico sobre esse problema dos getters e setters, 
o excesso de ifs e o relacionamento bidirecional entre classes. Quer praticar tudo 
isso com video aulas, respostas dos instrutores e correção dos seus exercícios? Con-
fira nosso novo curso online de boas práticas de orientação a objetos!
Fonte: Aniche (2012, on-line)1.
113
eu recomendo!
Java – A Referência Completa
Autor: Herbert Schildt 
Editora: Alta Books
Sinopse: em Java – A Referência Completa, tradução da oitava 
edição, o autor best-seller de livros de programação, Herb Schildt, 
mostra o necessário para desenvolver, compilar, depurar e exe-
cutar programas Java. Atualizado para esta plataforma, Edição 
Padrão 7 (Java SE7), o guia detalhado abrange toda linguagem Java, incluindo a 
sua sintaxe, as suas palavras-chave e os seus princípios fundamentais de progra-
mação. Também serão encontradas, no livro, informações de elementos-chave da 
biblioteca Java API. JavaBeans, servlets, applets e swing são estudados e exemplos 
reais demonstram o Java em ação. Além disso, as novas funções do Java SE 7, 
como o try-with-resources, strings em switch, inferência de tipo com o operador 
diamante, NIO.2 e os Frameworks Fork/Join são discutidos em detalhes.
livro
114
eu recomendo!
Note que o uso de herança aumenta o acoplamento entre as classes, isto é, o 
quanto uma depende de outra. A relação entre as classes mãe e filha é muito 
forte e isto faz com que o programador das classes filhas tenha que conhecer 
a implementação da classe mãe e vice-versa. Desse modo, fica difícil fazer uma 
mudança pontual no sistema. Por exemplo, imagine se tivermos que realizar al-
guma alteração em nossa classe Funcionário, mas não quiséssemos que todos os 
funcionários sofressem a mesma mudança. Precisaríamos passar por cada uma 
das filhas de Funcionário, verificando se ela se comporta como deveria ou se pre-
cisamos sobrescrever o tal método modificado. 
Este é um problema da herança, e não do polimorfismo, o que resolveremos mais 
tarde, com a ajuda das interfaces.
https://www.caelum.com.br/apostila-java-orientacao-objetos/heranca-reescrita-
-e-polimorfismo/#polimorfismo
A herança é um princípio da POO que permite a criação de novas classes a partir 
de outras previamente criadas. Estas são chamadas de subclasses, ou classes de-
rivadas; e as já existentes, que deram origem às subclasses, são chamadas de su-
perclasses, ou classes base. Desse modo, é possível criar uma hierarquia, tornan-
do, assim, algumas classes mais amplas e outras, mais específicas. Uma subclasse 
herda métodos e atributos de sua superclasse; apesar disso, pode escrevê-los 
novamente para uma forma mais específica de representar o comportamento do 
método herdado.
http://www.devmedia.com.br/entendendo-e-aplicando-heranca-em-java/24544
Veja, neste artigo, os conceitos, a utilização, a implementação e a importância do 
polimorfismo. Veremos, também, onde o polimorfismo é utilizado e de que forma 
ele pode ajudar a termos projetos melhores.
http://www.devmedia.com.br/uso-de-polimorfismo-em-java/26140
conecte-se
4
CLASSES
ABSTRATAS
e Interfaces
PLANO DE ESTUDO 
A seguir, apresentam-se as aulas que você estudará nesta unidade: • O que é classe abstrata? • O que 
são interfaces? • Comparando interfaces e classes abstratas.
OBJETIVOS DE APRENDIZAGEM 
• Entender o que é classe abstrata • Entender o que é interface • Relacionar interfaces e classes abstratas.
PROFESSORES 
Prof. Dr. Edson A. Oliveira Junior
Prof. Me. Rafael Alves Florindo
INTRODUÇÃO
Caro(a) aluno(a), nesta unidade, compreenderemos, conceitual e pratica-
mente, o que são classes abstratas e interfaces. Implementaremos, também, 
sistemas simples para cada tópico estudado. O objetivo focal é elucidar as 
dúvidas referentes a esses dois conceitos importantes no paradigma de 
programação orientada a objetos. 
Primeiramente, iniciaremos o nosso estudo com o recurso de classes 
abstratas. A finalidade de uma classe abstrata, em uma modelagem UML, 
é a de funcionar como um modelo para novas classes que poderão ser 
estendidas a partir dela, ou seja, para as suas subclasses. Ao contrário das 
interfaces, as classes abstratas podem conter campos (atributos) que não 
são static e final, e elas podem conter métodos não abstratos implementa-
dos. Tais classes abstratas são semelhantes às interfaces, exceto porque que 
elas fornecem uma implementação parcial, deixando as subclassescom-
pletarem a execução. Se uma classe abstrata contém, apenas, declarações 
de métodos abstratos, ela deve ser declarada como interface e não como 
uma classe abstrata.
Na sequência, após internalizarmos os conceitos referentes às classes 
abstratas, estudaremos as interfaces. Estas podem ser implementadas por 
classes em qualquer lugar na hierarquia, quer estejam ou não relacionadas 
umas com as outras. Em comparação, a classe abstrata é uma subclasse 
de classes semelhantes (as partes implementadas da abstrata), mas que, 
também, tem algumas diferenças (os métodos abstratos). As interfaces não 
possuem atributos, apenas métodos e, dessa forma, cumprem com o papel 
de contrato entre o desenvolvedor e a modelagem.
Após vermos os recursos apresentados, os colocaremos em prática, 
durante o nosso estudo, em algumas aplicações. Bom estudo!
U
N
IC
E
S
U
M
A
R
117
1 
O QUE É 
CLASSE ABSTRATA?
Uma classe abstrata é desenvolvida para representar classes e conceitos abstratos. 
Ela é sempre uma superclasse que não permite que nenhum objeto seja criado a 
partir dela, ou seja, não pode ser instanciada. O uso das classes abstratas é dirigido 
para a construção de classes que constituirão um modelo, isto é, classes abstratas 
servirão como especificações básicas de novas, que serão implementadas por 
meio do mecanismo de herança. Assim, uma classe abstrata deve ser estendida, 
ou seja, deve ser a classe-base de outra, mais específica, que contenha os detalhes 
que não puderam ser incluídos na superclasse (abstrata). Para formalizar que 
uma classe seja abstrata, usamos a palavra reservada abstract antes da palavra 
reservada class (DEITEL; DEITEL, 2017). Vejamos um exemplo, na Figura 1:
public abstract class ItemAbstrato {
}
Figura 1 - Classe abstrata / Fonte: os autores.
Métodos abstratos são declarados com o modificador abstract. Se uma classe tiver 
algum método abstrato, ela, também, deverá, obrigatoriamente, ser declarada com 
o modificador abstract. Os métodos de uma classe abstrata, classificados como 
abstratos, devem terminar sempre com ; (ponto e vírgula), e a classe que a estender 
deverá implementá-los. Vejamos um exemplo, na Figura 2, de método abstrato:
U
N
ID
A
D
E
 4
118
public abstract class ItemAbstrato {
public abstract void cadastrar ();
}
Figura 2 - Classe abstrata / Fonte: os autores. 
Note que esses métodos não têm uma implementação, isto é, não possuem um 
corpo delimitado por chaves com qualquer código. Uma classe, também, pode ser 
declarada abstrata, mesmo que tenha um método não abstrato, ou a combinação 
de métodos abstratos e não abstratos. Veja o exemplo na Figura 3, a seguir:
public abstract class ItemAbstrato {
public abstract void cadastrar ();
public void topo (){
System.out.println("Topo!");
}
}
Figura 3 - Classe abstrata / Fonte: os autores.
Como, geralmente, as classes abstratas pertencem ao nível superior de uma hierarquia 
de classes, recomenda-se que contenham tanto código quanto possível, deixando 
para as suas subclasses, apenas, as implementações específicas dos métodos abstratos.
É importante lembrar que uma classe abstrata que herda de outra não preci-
sará fornecer implementação de todos os métodos abstratos herdados.
Modelando um projeto com classes abstratas
Agora que entendemos o que é classe abstrata, implementaremos um simples 
sistema de locadora de DVDs e CDs, utilizando os mais variados recursos que 
as classes abstratas oferecem. Lembrando que o sistema a ser desenvolvido é, 
meramente, instrutivo para que você possa compreender o funcionamento deste 
componente importante da linguagem orientada a objetos. 
É essencial observar que o uso do conceito de classes abstratas precisa ser mode-
lado nas atividades de análise e design do projeto, caso contrário, se usarmos a técnica 
U
N
IC
E
S
U
M
A
R
119
de codificação direta, talvez, nunca apareça a necessidade de usar esse conceito. Na 
Figura 4, apresentamos a representação do diagrama de classe do sistema de locadora. 
Figura 4 - Diagrama de classe do sistema de locadora / Fonte: os autores.
A modelagem anterior demonstra uma árvore de herança com uma classe abs-
trata (ItemAbstrato) e duas concretas (Dvds e Cds). Observe que tanto a classe 
quanto os métodos abstratos estão representados com a fonte em itálico, e este 
comportamento representa um padrão nas modelagens UML.
Implementando um Projeto com Classes Abstratas
Seguiremos a modelagem da figura anterior e implementaremos um sistema 
simples de locadora de DVDs e CDs. 
Criando a classe abstrata ItemAbstrato
Primeiramente, criaremos um projeto no NetBeans chamado ItemAbstrato. Des-
marque o campo Criar Classe Principal; em seguida, crie uma classe nova com o 
nome ItemAbstrato e coloque como nome do pacote locadora.
ItemAbstrato
- codigo : int
- titulo : String
- dataEmprestimo : String
- dataDevolucao : String
- situacaoItem : String
+ cadastrar() : void
+ emprestar() : void
+ devolver() : void
Dvd
+ Dvd() : void
+ vender() : void
+ cadastrar() : void
+ emprestar() : void
+ devolver() : void
+ imprimir() : void
Cds
+ vender() : void
+ cadastrar() : void
+ imprimir() : void
U
N
ID
A
D
E
 4
120
Os métodos set são, comumente, chamados de métodos modificadores porque, geral-
mente, alteram um valor. Métodos get são, comumente, chamados métodos acessores ou 
métodos de consulta. Um método predicado testa se uma condição é verdadeira ou falsa.
Fonte: Deitel e Deitel (2017, p. 277).
conceituando
Figura 5 - Criando a classe ItemAbstrato / Fonte: os autores.
Agora que temos a nossa classe, insira a palavra abstract antes de class ItemAbs-
trato e, também, os seguintes atributos e métodos abstratos da figura a seguir. 
Após isto, gere os respectivos gets e sets dos atributos.
Figura 6 - Classe abstrata ItemAbstrato / Fonte: os autores.
U
N
IC
E
S
U
M
A
R
121
Observe que a nossa classe ItemAbstrato apresenta a definição de uma classe abs-
trata que representa um item de uma locadora. Nesta classe, definimos atributos 
e métodos comuns a um DVD e a um CD. Como a nossa intenção é analisar o 
comportamento de classes abstratas, não serão implementados, aqui, todos os 
atributos e objetos que poderiam existir em uma locadora real, mas, sim, o ele-
mentar para compreendermos quando devemos usar classes abstratas.
Criando a classe Dvd que herdará a classe ItemAbstrato
Agora, criaremos outra classe chamada Dvd, que herdará a classe ItemAbstrato. 
Para isto, basta acrescentar a palavra-chave extends e, logo após, o nome da classe 
que desejamos herdar os métodos e atributos, no caso, ItemAbstrato. Veja, na 
figura a seguir, como ficou a nossa classe:
Figura 7 - Classe Dvd / Fonte: os autores.
Observe, na figura anterior, que o NetBeans IDE faz uma marcação no 
nome da classe Dvd, indicando que devemos implementar os métodos da 
classe pai, ItemAbstrato. Para isto, basta posicionar o ponteiro do mouse 
sobre o nome da classe e pressionar as teclas alt+enter para abrir o menu, 
que implementará todos os métodos automaticamente, ou você pode uti-
lizar o alt+insert e selecionar quais métodos você deseja implementar. 
Lembrando que uma classe é obrigada a implementar todos os métodos 
abstratos da classe pai.
U
N
ID
A
D
E
 4
122
Figura 8 - Classe Dvd / Fonte: os autores.
Após gerar os métodos, a nossa classe Dvd ficará igual ao código a seguir:
Figura 9 - Classe Dvd / Fonte: os autores.
Observe que foram gerados todos os métodos abstratos da classe ItemAbstrato. Caso 
o NetBeans IDE gere, automaticamente, um código para cada método, basta igno-
rá-los e, para isto, é só deletá-los ou comentá-los. Note que foi gerada uma anotação 
acima dos métodos: @Override. Embora não seja necessário usar essa anotação, re-
comendamos que o faça, pois você terá a vantagem de o compilador verificar algum 
erro de ortografia e/ou erro na combinação dos parâmetros no método da classe pai 
e, também, tornará o seucódigo mais fácil de ser compreendido. 
U
N
IC
E
S
U
M
A
R
123
Agora, é necessário implementar o código de cada método. Como o nosso ob-
jetivo é o estudo das classes abstratas, aqui, simplificaremos o código. Veja, a seguir, 
a implementação de um projeto com classes abstratas no código para cada método:
package Locadora;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Dvd extends ItemAbstrato {
 SimpleDateFormat sdf = new SimpleDateFormat("dd/mm/
yyyy");
 @Override
 public void cadastrar() {
 this.setCodigo(1);
 this.setTitulo("Senhor dos Anéis");
 this.setSituacaoItem("L");
 System.out.println(
 "\nDVD Cadastrado: " +
 "\nCod: " + this.getCodigo() +
 "\nTítulo: " + this.getTitulo() +
 "\nSituação: " + this.getSituacaoItem());
 }
 @Override
 public void emprestar() {
 setSituacaoItem("E");
 setDataEmprestimo(sdf.format(new Date())); 
 System.out.println(
 "\nDVD Emprestado:" + this.getTitulo() +
 "\nSituação:" + this.getSituacaoItem() +
 "\nData empréstimo:" + this.getDataEm-
prestimo());
 }
 @Override
 public void devolver() {
 setSituacaoItem("L");
U
N
ID
A
D
E
 4
124
 setDataDevolucao(sdf.format(new Date())); 
 System.out.println(
 "\nDVD Devolvido:" + this.getTitulo() +
 "\nSituação:" + this.getSituacaoItem() +
 "\nData empréstimo: " + this.getDataDe-
volucao());
 }
 
 public void imprimir(){
 System.out.println("Imprimir Lista de DVDs 
utilizando método concreto da classe DVD");
 }
}
Observe, no código anterior, que utilizamos todos os atributos da classe ItemAbs-
trato e, também, implementamos um novo método concreto na classe DVD, o im-
primir( ). Note que estamos utilizando a classe SimpleDateFormat("dd/
mm/yyyy"), instanciando-a no objeto SimpleDateFormat sdf = new 
SimpleDateFormat("dd/mm/yyyy");. A classe SimpleDateFormat é 
usada para a formatação e a análise de datas. Permite formatar a data em texto, 
analisando o texto em data e a normalização. Depois de instanciada a classe, basta 
chamar o método format() e, dentro, passar um parâmetro para a função.
Criando a classe CD que herdará a classe DVD
Agora, criaremos mais uma classe chamada Cds, e estenderemos da classe DVD, 
conforme pode ser visto na Figura 10:
Figura 10 - Classe Cds / Fonte: os autores. 
U
N
IC
E
S
U
M
A
R
125
Observe que, desta vez, o NetBeans não destacou o nome da classe forçando a 
implementação dos métodos da classe herdada, pois esta não é uma classe abs-
trata, como é a classe ItemAbstrato. Porém, assim como a classe Dvd, que 
herda, diretamente, da classe abstrata, a classe Cds passa a ter a possibilidade de 
reutilizar todos os atributos e métodos da classe ItemAbstrato e Dvd bem 
como definir as suas particularidades e usá-las.
Dessa forma, implementaremos a classe CDs conforme o código:
package Locadora;
public class Cds extends Dvd {
 @Override
 public void cadastrar() {
 this.setCodigo(1);
 this.setTitulo("The Best of Joy Division");
 this.setSituacaoItem("L");
 System.out.println(
 "\nCD Cadastrado: " +
 "\nCod: " + this.getCodigo() +
 "\nTítulo: " + this.getTitulo() +
 "\nSituação: " + this.getSituacaoItem());
 }
 @Override 
 public void imprimir(){
 System.out.println("Imprimir Lista de CDs 
utilizando método concreto da classe DVD");
 }
 public void vender(){
 System.out.println("CD vendido utilizando mé-
todo concreto da classe CDs");
 }
}
Observe que estamos utilizando métodos da classe ItemAbstrato e, também, 
da classe Dvd, além de escrever métodos exclusivos da classe Cds, como o méto-
do vender( ). A classe Cds herda esses métodos, pois eles são públicos e concretos.
U
N
ID
A
D
E
 4
126
Regras das Classes e dos Métodos Abstratos
Alguns pontos interessantes das imagens anteriores exemplificam algumas das 
regras de criação das classe e dos métodos abstratos, que são:
 ■ Os métodos construtores não podem ser declarados abstratos. Mesmo 
que a classe abstrata não possa ser instanciada, os seus construtores po-
dem inicializar os campos da classe que serão usados por subclasses, o 
que é imprescindível em todos os casos, praticamente.
 ■ Métodos declarados como abstratos não podem ser privados (private).
 ■ Classes abstratas não podem conter métodos estáticos (static).
 ■ Os campos de uma classe abstrata serão herdados pelas classes des-
cendentes e poderão ser usados por instâncias delas, a não ser que 
sejam declarados private.
Criando a classe Programa para executar o nosso sistema
Para finalizar o nosso sistema, criaremos mais uma classe com o método main, 
chamada Programa. Nela, criaremos um menu e um método de escolha para 
que possamos chamar todos os métodos implementados em nosso exemplo. 
A seguir, no código dessa classe:
package Locadora;
import java.util.Scanner;
public class Programa {
 public static void main(String[] args) {
 int opcao;
 Dvd dvd = new Dvd();
 Cds cds = new Cds();
 while(true){
 System.out.println();
 System.out.println("------------------"); 
 System.out.println("0 - Sair");
 System.out.println("1 - Cadastrar DVD");
 System.out.println("2 - Emprestar DVD");
U
N
IC
E
S
U
M
A
R
127
 System.out.println("3 - Devolver DVD");
 System.out.println("4 - Cadastrar CD");
 System.out.println("5 - Vender CD");
 System.out.println("6 - Imprimir CDs");
 System.out.println("Opção: ");
 Scanner scan = new Scanner(System.in);
 opcao = scan.nextInt();
 System.out.println("------------------");
 if(opcao == 0){
 System.exit(0);
 }
 switch(opcao){
 case 1:
 dvd.cadastrar();
 break;
 case 2:
 dvd.emprestar();
 break;
 case 3:
 dvd.devolver();
 break;
 case 4:
 cds.cadastrar();
 break;
 case 5:
 cds.vender();
 break;
 case 6:
 cds.imprimir();
 break;
 }
 }
 }
}
U
N
ID
A
D
E
 4
128
Explicando o código
Observe que criamos um laço de repetição com o método while( ), sendo 
a condição de parada a variável opção igual a 0. Fizemos uso, também, da classe 
java.util.Scanner, que permite a leitura de dados vindos do teclado. 
Agora que você já implementou o código anterior, execute o programa e visualize 
os resultados na saída do NetBeans IDE. 
Importante lembrar que o uso de classes abstratas é realizado com classes 
que têm métodos e atributos em comum ou, pelo menos, a maioria. Em nosso 
exemplo, a mídia DVD possui muito em comum com CDs. Além dos atributos, 
os métodos podem ser utilizados para ambas as classes. O nosso programa de 
locadora se limitou a cadastrar e a vender os CDs, o que não impediria de colo-
cá-los para serem alugados, assim como os DVDs.
Há uma série de situações, em engenharia de software, em que é importante que 
diferentes grupos de programadores concordem com um “contrato”, o qual, por 
sua vez, expõe a forma como o software interagirá. Cada grupo deve ser capaz de 
escrever o seu código, sem qualquer conhecimento de como o código do outro 
grupo está escrito. De modo geral, isto se aplica ao importante componente da 
orientação a objetos, conhecido como interfaces. 
2 
O QUE SÃO 
INTERFACES?
U
N
IC
E
S
U
M
A
R
129
A interface é um recurso da orientação a objeto, utilizado em Java, que define 
ações, obrigatoriamente, executadas, mas que cada classe pode executar de forma 
diferente (DEITEL; DEITEL, 2017). 
A seguir, temos o exemplo de uma interface denominada InterfaceControle:public interface InterfaceControle {
 
}
Na linguagem de programação Java, uma interface é um tipo de referência 
semelhante a uma classe, que pode ter apenas constante, assinaturas de mé-
todos e tipos aninhados, não há corpo de método. Interfaces não podem ser 
instanciadas, elas só podem ser implementadas por classes ou estendidas por 
outras interfaces. Por que isto acontece? Esse fenômeno se deve ao fato de que 
muitos objetos (classes) podem possuir a mesma ação (método), mas podem 
executá-la de maneira diferente.
Usando um exemplo bem remoto, podemos ter uma interface chamada Elemen-
toDiagrama, que possui a assinatura do método desenhar() e redimen-
sionar(). Ou seja, toda classe de ElementoDiagrama que for implementada 
deve dizer que a implementação dos métodos desenhar() e redimensio-
nar() funcionam. Portanto, se temos uma classe chamada Retangulo, e outra 
chamada Circulo, ambas implementando a interface ElementoDiagrama, então, 
nestas duas classes, devemos codificar a forma como cada um fará o desenhar() 
e o redimensionar(). Vejamos o diagrama de classe a seguir:
Figura 11 - Implementação da interface ElementoDiagrama / Fonte: os autores.
Retangulo
- comprimento : double
- altura : double
+ desenhar() : void
+ redimensionar() : void
Circulo
- raio : double
+ desenhar() : void
+ redimensionar() : void
ElementoDiagrama
<<interface>>
+ desenhar() : void
+ redimensionar() : void
U
N
ID
A
D
E
 4
130
Características das interfaces
De acordo com Deitel e Deitel (2017), uma interface tem as seguintes características:
 ■ Todos os métodos definidos são, implicitamente, do tipo public ou abstract.
Por esta razão, ao declarar um método em uma interface, não é necessário 
fornecer a palavra-chave public. 
Figura 12 – InterfaceControle / Fonte: os autores.
 ■ Uma interface pode estender mais de uma interface. É importante lembrar 
que uma classe pode estender, somente, de outra classe.
Figura 13 - Estendo InterfaceControle / Fonte: os autores.
A classe que implementa uma interface deve, obrigatoriamente, implementar 
todos os métodos definidos na interface.
Figura 14 - A obrigatoriedade de implementar uma interface / Fonte: os autores.
Implementando os métodos, temos:
Figura 15 - Implementando o método conectarBanco / Fonte: os autores.
U
N
IC
E
S
U
M
A
R
131
 ■ Uma interface é, formalmente, uma classe abstrata, somente com atributos 
constantes (final) e estáticos (static) e, ainda, métodos sem corpo. Estes 
deverão ser implementados pelas classes que implementarão a interface. 
É importante observar que os atributos, na interface, precisam ser inicializados. 
Vejamos um exemplo na Figura 16:
Figura 16 - Inicializando variáveis estáticas na interface / Fonte: os autores. 
Voltando ao nosso exemplo de Interface ElementoDiagrama, crie um novo 
projeto Java, com o nome de ElementoDiagrama e, depois, crie três pacotes 
e as suas respectivas classes.
Após ter criado a estrutura de pacotes e classes, 
vamos codificá-los.
Iniciamos pela interface Ele-
mentoDiagrama. Note que foram imple-
mentados dois métodos: public void 
desenhar(); e public void re-
desenhar(); ambos com (;) no final da 
assinatura do método. Dessa forma, as clas-
ses que implementam esta interface deverão 
codificar estes métodos.
package Interfaces;
public interface ElementoDiagrama {
 public void desenhar();
 public void redesenhar();
}
Figura 17 - Estrutura de pacotes do 
projeto ElementoDiagrama.
Fonte: os autores. 
U
N
ID
A
D
E
 4
132
Após codificada a interface anterior, temos a classe public class Retan-
gulo, que está implementando a interface implements ElementoDia-
grama, junto com a codificação dos métodos public void desenhar() 
{} e public void redesenhar(){}. 
package Classes;
import Interfaces.ElementoDiagrama;
public class Retangulo implements ElementoDiagrama{
 @Override
 public void desenhar() {
 System.out.println("Desenhando um Retângulo");
 }
 @Override
 public void redesenhar() {
 System.out.println("Redesenhando um Retângulo");
 }
}
Após codificada a interface, temos a classe public class Circulo, que 
está implementando a interface implements ElementoDiagrama, junto 
com a codificação dos métodos public void desenhar(){} e public 
void redesenhar(){}. 
package Classes;
import Interfaces.ElementoDiagrama;
public class Circulo implements ElementoDiagrama{
 @Override
 public void desenhar() {
 System.out.println("Desenhando um Círculo");
 }
 @Override
 public void redesenhar() {
 System.out.println("Redesenhando um Círculo");
 }
}
U
N
IC
E
S
U
M
A
R
133
Para testar a interface e as classes, editaremos a classe principal que está 
no pacote Programa.
package Programa;
import Classes.Retangulo;
import Classes.Circulo;
public class Principal {
 public static void main(String[] args) {
 Retangulo ret = new Retangulo();
 Circulo cir = new Circulo();
 
 ret.desenhar();
 ret.redesenhar();
 cir.desenhar();
 cir.redesenhar(); 
 }
}
Modelando um Projeto com Interfaces
Após compreendermos as interfaces e o seu comportamento, implementaremos um 
simples sistema de cadastro de Blu-Rays, utilizando a interface como principal recurso. 
As interfaces são um 
conjunto de operações 
que definem os servi-
ços de uma classe ou 
de um componente. 
Em nosso caso, as in-
terfaces existirão ape-
nas na classe. Veremos, 
a seguir, na Figura 18, 
o diagrama de classe 
do nosso projeto de 
cadastro de Blu-Rays. 
BluRay
- listaBluRay : Vector
+ cadastrarBluRay(obj : ItemBluRay) : void
ItemBluRay
- preco : double
- nomeCliente : String
InterfaceBluRay
<<interface>>
+ imprimirLista() : void
+ adicionarLista(obj : ItemBluRay) : void
+ PROMOCAO : double
0..*0
Figura 18 - Diagrama de classe do sistema cadastro de Blu-Ray.
Fonte: os autores. 
U
N
ID
A
D
E
 4
134
A Figura 18 mostra as características básicas para representar interfaces. A linha 
tracejada e com uma ponta de flecha vazada demonstra que a classe Blu-ray 
implementa a interface. 
Outra forma de mostrar que uma classe implementa uma interface é dese-
nhar uma linha com um círculo em uma das extremidades, com o nome dessa 
interface. As interfaces e os seus métodos, em Java, sempre são abstratos. Estra-
nhamente, ambos não aparecem em itálico, como ocorre com as classes abstratas 
e os métodos abstratos em classes.
Implementando um Projeto com Interfaces
Seguiremos a modelagem da figura anterior e implementaremos um sistema de 
vendas de Blu-Rays.
Criando a classe ItemBluRay
Primeiramente, criaremos um projeto, no NetBeans, chamado BluRayIn-
terface; assim, desmarque o campo Criar Classe Principal. Em seguida, crie 
uma classe nova com o nome ItemBluRay e coloque como nome do pacote 
BluRayInterface. Na classe ItemBluRay, criaremos dois atributos e 
implementaremos os métodos gets e sets.
package BluRayInterface;
public class ItemBluRay {
 private double preco;
 private String nomeCliente;
 public double getPreco() {
 return preco;
 }
 public void setPreco(double preco) {
 this.preco = preco;
 }
U
N
IC
E
S
U
M
A
R
135
 public String getNomeCliente() {
 return nomeCliente;
 }
 public void setNomeCliente(String nomeCliente) {
 this.nomeCliente = nomeCliente;
 } 
}
Esta classe será o nosso objeto para armazenarmos os dados salvos em nosso cadastro.
Criando a interface InterfaceBluRay
Para criar uma interface, no NetBeans IDE, basta clicar com o botão direito do 
mouse sobre o pacote do projeto e, no menu, escolher Novo > Interface 
Java... e adicionar InterfaceBluRay como nome da interface. Em seguida, 
clique em Finalizar. Nesta interface, criaremos um atributo estático e dois méto-
dos, conforme a figura a seguir:
package BluRayInterface;
public interface InterfaceBluRay {
 final static double PROMOCAO = 20;
 void adicionarLista(ItemBluRay obj);
 void imprimirLista();
}
Observeque estamos utilizando um atributo do tipo final e static. A instrução 
final indica que a classe, o método ou a variável, assim declarada, tem uma única 
atribuição que se mantém constante, ou seja, não pode ser alterada no decorrer do 
processamento. A instrução static é utilizada para criar uma variável que poderá ser 
acessada por todas as instâncias de objetos desta classe como uma variável comum. 
Em nosso exemplo, atribuímos para a variável estática PROMOCAO o valor 
de 20, e ela será responsável por gerar o desconto em nosso sistema. 
U
N
ID
A
D
E
 4
136
A vantagem em ter um atributo estático e final é que, ao alterar a variável 
estática, todo o sistema receberá o novo valor atualizado. Observe que os méto-
dos estão sem os modificadores de acesso public e, conforme apresentado ante-
riormente, não é necessário declarar os modificadores de acesso, pois todos os 
métodos e atributos de uma interface são públicos.
Criando a classe Blu-Ray e estendendo a interface
Agora, crie a classe Blu-Ray e acrescente a palavra reservada implements e a nossa 
interface InterfaceBluRay. Observe abaixo que o NetBeans IDE destacou a nossa 
classe para que seja criado todos os métodos exigidos pela interface. Ela obriga o uso 
de todos os métodos declarados, porém é você quem decide como implementá-los.
package BluRayInterface;
import java.util.Scanner;
import java.util.Vector;
public class Bluray implements InterfaceBluRay{
 private Vector<ItemBluRay>ListaBluray = new Vec-
tor<ItemBluRay>();
 @Override
 public void adicionarLista(ItemBluRay obj) {
 this.ListaBluray.add(obj);
 }
 @Override
 public void imprimirLista() {
 System.out.println("Lista de Blu Ray");
 for(int i = 0; i < this.ListaBluray.size(); i++){
 System.out.println();
 System.out.println("Nome do Cliente");
 System.out.println(this.ListaBluray.get(i).getNo-
meCliente());
 System.out.println("Preço do Blu-Ray");
 System.out.println(this.ListaBluray.get(i).getPre-
U
N
IC
E
S
U
M
A
R
137
co());
 }
 System.out.println("--------------------");
 System.out.println();
 }
}
Nesta classe, criamos um vetor de ItemBluray para armazenar os objetos 
ItemBluRay e, assim, obter uma lista. O método adicionarLista() recebe, por 
parâmetro, o objeto salvo na classe Programa que será implementado a seguir. O 
método imprimirLista() apresenta a relação de BluRay salvos no programa.
Ainda falta um método para realizarmos os cadastros de todos os Blu-Rays. 
Ele será criado diretamente na classe, pois ele não foi implementado na interface, 
conforme o código a seguir:
package BluRayInterface;
import java.util.Scanner;
import java.util.Vector;
public class Bluray implements InterfaceBluRay{
 private Vector<ItemBluRay>ListaBluray = new Vec-
tor<ItemBluRay>();
 @Override
 public void adicionarLista(ItemBluRay obj) {
 this.ListaBluray.add(obj);
 }
 @Override
 public void imprimirLista() {
 System.out.println("Lista de Blu Ray");
 for(int i = 0; i < this.ListaBluray.size(); i++){
 System.out.println();
 System.out.println("Nome do Cliente");
 
System.out.println(this.ListaBluray.get(i).getNomeCliente());
 System.out.println("Preço do Blu-Ray");
U
N
ID
A
D
E
 4
138
 System.out.println(this.ListaBluray.get(i).getPreco());
 }
 System.out.println("--------------------");
 System.out.println();
 } 
 public void cadastrarBlueRay(ItemBluRay obj){
 Scanner scan = new Scanner(System.in);
 System.out.println("Nome do cliente");
 obj.setNomeCliente(scan.nextLine());
 System.out.println("Preço:");
 obj.setPreco(scan.nextDouble());
 }
}
O método cadastrarBluRay() recebe, por parâmetro, o objeto ItemBluRay 
da classe Programa, que será implementado a seguir.
Criando a Classe Programa
Para finalizar, criaremos a classe Programa para executar o nosso projeto. 
Confira o código para essa classe:
package BluRayInterface;
import java.util.Scanner;
public class Programa {
 public static void main(String[] args) {
 Bluray objBluray = new Bluray();
 ItemBluRay objItem;
 while(true){
 
 objItem = new ItemBluRay();
 System.out.println("1 - Cadastrar Blu-Ray");
 System.out.println("2 - Imprimir lista de Blu-Ray");
U
N
IC
E
S
U
M
A
R
139
 System.out.println("3 - Cadastrar Blu-Ray com Desconto");
 System.out.println("4 - Fim");
 System.out.println("Entre com a opção desejada: ");
 Scanner scan = new Scanner(System.in);
 int opcao = scan.nextInt();
 if(opcao == 4)
 break;
 switch(opcao){
 case 1:
 objBluray.cadastrarBlueRay(objItem);
 objBluray.adicionarLista(objItem);
 break;
 case 2:
 objBluray.imprimirLista();
 break;
 case 3:
 objBluray.cadastrarBlueRay(objItem);
 System.out.println("Valor do Blu-Ray com 
promoção de: " + InterfaceBluRay.PROMOCAO);
 double valorDesconto = objItem.getPre-
co() - (objItem.getPreco()*
 InterfaceBluRay.PROMOCAO)/100;
 objItem.setPreco(valorDesconto);
 objBluray.adicionarLista(objItem);
 System.out.println();
 System.out.println();
 break;
 default:
 System.out.println("Opção Inválida");
 
 break;
 }
 }
 }
}
U
N
ID
A
D
E
 4
140
Explicando o código
Na classe Programa, criamos uma instância da classe Blu-Ray, chamada objBlu-
ray, lembrando que instância e objeto são sinônimos. A criação do objeto envolve 
o operador new(), que foi o utilizado no código anterior. Em seguida, criamos a 
variável do tipo ItemBluRay, chamado objItem.
Criamos o método while(), que controla a saída ou a permanência no pro-
grama e, logo em seguida, instanciamos a variável do tipo objItem, que será 
responsável por salvar as informações de cada item de Blu-Ray no objeto Bluray. 
Utilizamos, também, a classe Scanner() para adquirir todas as opções do menu 
digitadas pelo usuário.
Observe que, por meio do objeto objBluray, temos acesso a todos os métodos 
da classe Bluray. E, na linha System.out.println("Valor do Blu-
-Ray com promoção de: " + InterfaceBluRay.PROMOCAO); 
fazemos uso, pela primeira vez, do atributo estático que criamos na Interface-
BluRay, lembra? Na linha double valorDesconto = objItem.
getPreco() - (objItem.getPreco() * InterfaceBluRay.
PROMOCAO) / 100; aproveitamos este recurso para realizar o cálculo de 
desconto ao cadastrar o Blu-Ray. Em nossa interface, definimos que o valor do 
desconto seria 20%. Caso, um dia, o desconto mude, basta alterar o valor da va-
riável estática e todos os programas que fazem uso dela serão atualizados auto-
maticamente. Pronto! Agora é só executar o programa e visualizar os resultados.
U
N
IC
E
S
U
M
A
R
141
Se você leu a seção de classes abstratas, talvez esteja se perguntando por que os 
projetistas da linguagem Java se deram ao trabalho de introduzir o conceito de 
interfaces? Por que aquela que criamos, a InterfaceBluRay, não pode ser, sim-
plesmente, uma classe abstrata?
Há, infelizmente, um sério problema com o uso de uma classe básica abstrata 
para expressar uma propriedade genérica. Uma classe só pode estender uma 
única classe. Suponha que a classe Bluray já estende outra diferente, digamos, 
Midia. Ela, então, não poderá estender uma segunda classe, mas cada uma pode 
implementar quantas interfaces quiser.
Outras linguagens de programação, especialmente o C++, permitem que 
uma classe tenha mais de uma superclasse. Esse recurso é chamado de herança 
múltipla. Os projetistas do Java optaram por não dar suporte à herança múltipla, 
porque ela torna a linguagem muito complexa (como no C++). Em vez disso, as 
interfacessuportam a maioria dos benefícios da herança múltipla e, ao mesmo 
tempo, evitam as complexidades e ineficiências.
A seguir, mostramos um quadro comparativo para tornar mais fácil a com-
preensão das diferenças e similaridades entre classes abstratas e interfaces.
3 
COMPARANDO 
INTERFACES
e classes Abstratas
U
N
ID
A
D
E
 4
142
Característica Interface Classe abstrata
Herança 
múltipla
Uma classe pode implementar 
diversas interfaces.
Uma classe pode herdar, 
somente, uma classe.
Implementa-
ção padrão
Uma interface não pode conter 
qualquer tipo de código, muito 
menos código padrão.
Uma classe abstrata pode for-
necer código completo, código 
padrão ou ter apenas a declara-
ção de seu esqueleto para ser, 
posteriormente, sobrescrita.
Constantes
Suporta, somente, constantes 
do tipo estática.
Pode conter constantes está-
ticas e de instância.
Componentes 
de terceiros
Uma implementação de uma 
interface pode ser incluída a 
qualquer classe de terceiros.
Uma classe de terceiros 
precisa ser reescrita para 
estender somente a partir da 
classe abstrata.
Homogenei-
dade
Se todas as diversas implemen-
tações compartilham a assinatu-
ra do método, então, a interface 
funciona melhor.
Se as várias implementações 
são todas do tipo e comparti-
lham um comportamento e um 
status comuns, então, a classe 
abstrata funciona melhor.
Manutenção
Se o código do seu cliente conver-
sa somente em termos de uma 
interface, você pode, facilmente, 
alterar a implementação concreta 
usando um método factory.
Idêntico.
Velocidade
Lento, requer trabalho extra 
para encontrar o método cor-
respondente na classe atual.
Rápido.
Clareza
Todas as declarações de cons-
tantes, em uma interface, são, 
presumidamente, públicas ou 
estáticas.
Você pode colocar código 
compartilhado em uma classe 
abstrata. Você pode usar códi-
go para computar o valor inicial 
de suas constantes e variáveis 
de instância ou estáticas.
Funcionalida-
des adicionais
Se você incluir um novo método em 
uma interface, você precisa ajustar 
todas as implementações dela.
Se você incluir um novo método 
em uma classe abstrata, você 
tem a opção de fornecer uma 
implementação padrão para ele.
Quadro 1 - Comparativo entre classe abstrata e interface / Fonte: os autores.
U
N
IC
E
S
U
M
A
R
143
CONSIDERAÇÕES FINAIS
Chegamos ao final de mais uma unidade e, nesta, abordamos as duas estruturas 
de importância na orientação a objetos, às classes abstratas e às interfaces. Estas 
estruturas são utilizadas para garantir uma estrutura coesa e íntegra no tocante 
ao desenvolvimento, agilizando ações corretivas ou de customização.
Em relação à classe abstrata, nota-se que ela pode conter tanto métodos 
abstratos quanto não abstratos, mas, se ao menos um deles for marcado com o 
estereótipo abstract, a classe, também, deverá ser marcada como abstrata. Não 
esqueça que a subclasse concreta (não abstrata) de uma classe abstrata terá de 
fornecer implementações de todos os métodos abstratos da superclasse, mas que 
uma classe abstrata não tem de implementar os métodos abstratos de sua super-
classe. Ainda, neste tópico, abordamos que uma classe abstrata nunca poderá ser 
instanciada, pois a sua única missão de vida é ser estendida.
Além disso, abordamos a implementação de interfaces. Aqui, você aprendeu 
que as interfaces podem estender outra (até mesmo várias) e que qualquer classe 
que implementar uma interface terá de implementar os métodos de todas as ou-
tras existentes na árvore de herança da interface que estiver sendo implementada.
Sendo assim, temos que as classes abstratas podem conter atributos, desde que 
não sejam static e final, e elas podem conter métodos não abstratos implementados. 
Tais classes abstratas são semelhantes às interfaces, exceto aquelas elas fornecem 
uma implementação parcial, deixando as subclasses completarem a execução. As 
interfaces funcionam como um contrato de desenvolvimento cujos métodos não 
podem ser implementados na interface.
Ao longo da unidade, trabalhamos com pequenos estudos de casos que 
visavam a nortear os seus estudos. Sendo assim, sugere-se que, a partir destes, 
criem-se novas soluções, pois, para um problema, podem surgir diversas soluções, 
desde que elas cheguem ao mesmo resultado.
144
na prática
1. Dado o código a seguir, assinale com V (verdadeiro) ou F (falso) as declarações que 
seguem referentes ao código a seguir: 
1. abstract class Automovel {
2. abstract short metodo1 () ;
3. short metodo2() { return (short) 420; }
4. }
5. 
6. abstract class MiniCarro extends Automovel {
7. // codigo faltando?
8. short metodo1() { return (short) 42; }
9. }
( ) O código será compilado sem alterações.
( ) A classe MiniCarro criará uma declaração abstract do metodo2() ou implemen-
tará esse método para permitir que o código seja compilado.
( ) É válido, mas não necessário, que a classe MiniCarro crie uma declaração 
abstrata do método metodo2() ou o implemente para permitir que o có-
digo seja compilado.
( ) Já que a linha 8 existe, a classe Automovel deve declarar o método metodo1(), 
de alguma maneira.
( ) Se a linha 6 fosse substituída por "MiniCarro extends Automovel { ", o código 
seria compilado.
( ) Se a classe Automovel não fosse abstrata, e o método metodo1() da linha 2 fosse 
implementado, o código não seria compilado.
Assinale a alternativa correta:
a) V - F - F - F - F - F.
b) F - V - V - F - V - F.
c) V - V - F - F - F - F.
d) V - F - V - V - F - V.
e) F - F - F - F - F - V.
145
na prática
2. Um dos recursos providos pela programação orientada a objetos, é a interface, devi-
do à sua força de "gerenciamento", ou seja, as interfaces são entidades que definem 
os métodos que as classes que a implementam a interface devem implementar 
obrigatoriamente, ou seja, um contrato. Sabemos que não se tratam de classes 
em si, mas um modelo para suas implementações (classes que virão a configurar 
os seus métodos). Com base nestas informações, assinale com V (verdadeiro) ou F 
(falso) as afirmações a seguir. 
( ) Toda classe que possui um método abstrato é, obrigatoriamente, uma classe abstrata.
( ) Uma classe abstrata pode ter métodos não abstratos (não marcados com a 
palavra-chave abstract).
( ) Para evitar erros de compilação, todo método de uma interface necessita ser 
marcado com a palavra-chave abstract.
( ) Tanto classes abstratas quanto interfaces necessitam ter um método ou uma variável.
( ) Uma classe não abstrata que herda de uma classe abstrata deve, obrigatoria-
mente, implementar todos os seus métodos herdados.
Assinale a alternativa correta:
a) V - F - F - F - F.
b) V - V - F - F - F.
c) F - V - F - F - F.
d) F - V - V - F - F.
e) F - F - F - F - V.
3. O uso de Interfaces é amplamente utilizado pelos desenvolvedores e programado-
res, pois permite a criação de códigos que especificam quais métodos uma classe 
deve implementar, sem definir como esses métodos serão tratados, ou seja, uma 
interface funciona como um contrato de especificações de métodos. Diante do con-
texto citado, avalie as afirmações a seguir sobre o uso de interfaces em Java.
I - Uma interface pode ser herdada.
II - Uma classe concreta pode implementar uma interface.
III - Uma interface pode conter métodos e atributos de classe.
IV - Uma classe abstrata pode implementar uma interface.
V - Uma interface pode ser implementada por outra interface.
146
na prática
É correto o que se afirma em:
a) I, apenas.
b) I e II, apenas.
c) II e IV, apenas.
d) II, IV e V, apenas.
e) I, II, III e IV, apenas.
4. Analise a modelagem a seguir, codifique as classes e crie uma instância de objeto.
5. Analise a modelagem a seguir, codifique as classes e crie uma instância de objeto.
Colaborador
- dataAdmisao : String
- salario : String
- cargo : String
+ cadastro() : void
Pessoa
<<abstract>>
+ <<abstract>> cadastro() : void
- nome : String
- dataNascimento : String
Livro
- autor :String
+ cadastro() : void
+ listar() : void
Controle
<<interface>>
+ cadastrar() : void
+ listar() : void
147
aprimore-se
INTERFACES
Java também oferece outra estrutura, denominada interface, com sintaxe similar a 
de classes, mas contendo apenas a especificação da funcionalidade que uma classe 
deve conter, sem determinar como essa funcionalidade deve ser implementada. 
Uma interface Java é uma classe abstrata para a qual todos os métodos são implici-
tamente abstract e public, e todos os atributos são implicitamente static e final. Em 
outros termos, uma interface Java implementa uma “classe abstrata pura”. A sintaxe 
para a declaração de uma interface é similar àquela para a definição de classes, po-
rém seu corpo define apenas assinaturas de métodos e constantes. 
A diferença entre uma classe abstrata e uma interface Java é que a interface 
obrigatoriamente não tem um “corpo” associado. Para que uma classe seja abstrata 
basta que ela seja assim declarada, mas a classe pode incluir atributos de objetos e 
definição de métodos, públicos ou não. Na interface, apenas métodos públicos po-
dem ser declarados — mas não definidos. Da mesma forma, não é possível definir 
atributos — apenas constantes públicas.
Enquanto uma classe abstrata é “estendida” (palavra chave extends) por classes 
derivadas, uma interface Java é “implementada” (palavra chave implements) por ou-
tras classes. Uma interface estabelece uma espécie de contrato que é obedecido por 
148
aprimore-se
uma classe. Quando uma classe implementa uma interface, garante-se que todas as 
funcionalidades especificadas pela interface serão oferecidas pela classe. Outro uso 
de interfaces Java é para a definição de constantes que devem ser compartilhadas 
por diversas classes. Neste caso, a recomendação é implementar interfaces sem 
métodos, pois as classes que implementarem tais interfaces não precisam tipica-
mente redefinir nenhum método. 
interface Coins {
 int
 PENNY = 1,
 NICKEL = 5,
 DIME = 10,
 QUARTER = 25,
 DOLAR = 100;
}
Class SodaMachine implements Coins {
 int price = 3*QUARTER;
 //...
}
Fonte: Ricarte (2001, p. 29-30).
149
eu recomendo!
Java – Como Programar
Autor: Paulo Deitel e Harvey Deitel
Editora: Pearson
Sinopse: milhões de alunos e profissionais aprenderam progra-
mação e desenvolvimento de software com os livros Deitel®. 
Java – Como Programar, 10ª edição, fornece uma introdução 
clara, simples, envolvente e divertida à programação Java, com 
ênfase inicial em objetos. Os destaques incluem: rica cobertura dos fundamentos 
com exemplos reais; apresentação com ênfase inicial em classes e objetos; uso 
com Java™ SE 7, Java™ SE 8 ou ambos; Java™ SE 8 abordado em seções modu-
lares opcionais; lambdas, fluxos e interfaces funcionais usando método padrão 
e estático do Java SE 8; Swing e GUI do JavaFX: elementos gráficos e multimídia; 
conjunto de exercícios “Fazendo a Diferença”; tratamento de exceções integrado; 
arquivos, fluxos e serialização de objetos; concorrência para melhor desempenho 
com multiprocessamento. O livro também tem o conteúdo principal para cursos 
introdutórios; outros tópicos: recursão, pesquisa, classificação, coleções genéri-
cas, estruturas de dados, multithreading, banco de dados (JDBC ™ e JPA). 
livro
Com o início do paradigma de desenvolvimento OO, alguns termos se tornaram 
corriqueiros no mundo de programadores e analistas de sistema. Classes, heran-
ça e polimorfismo são alguns deles.
http://www.devmedia.com.br/interfaces-x-classes-abstratas/13337
conecte-se
5
ESTUDO DE CASO: 
ANÁLISE CLÍNICA
PLANO DE ESTUDO 
A seguir, apresentam-se as aulas que você estudará nesta unidade: • Estudo de caso • Passo a passo 
para a elaboração do diagrama de classes • Implementação do software.
OBJETIVOS DE APRENDIZAGEM 
• Apresentar o fluxo de funcionamento para exemplificar o desenvolvimento de um sistema a partir da 
modelagem do sistema • Realizar um passo a passo da elaboração do diagrama de classes na visão do 
analista de software • Rever a modelagem do diagrama de classe na visão do desenvolvedor e do analista.
PROFESSORES 
Me. Márcia Cristina Dadalto Pascutti
Esp. Janaina Aparecida de Freitas
Me. Rafael Alves Florindo
Esp. Victor de Marqui Pedroso
INTRODUÇÃO
Olá, caro(a) aluno(a)! Chegamos à última unidade do livro de Programação 
III. Aqui, abordaremos o estudo de caso de um laboratório de análises clínicas, 
desde a concepção da modelagem até a implementação na linguagem Java.
No primeiro tópico, apresentaremos a você o documento de requi-
sitos de um laboratório de análises clínicas. Neste documento, o cliente 
listou todos os desejos de funcionalidades e as especificou. Além dessas 
especificações, ele detalhou o fluxo de como deve funcionar o sistema. 
Esse processo tem um grau de relevância alto, pois, caso não compreen-
da o que é solicitado, o restante da modelagem ficará precária. Conse-
quentemente, quando chegar à implementação, é possível que ocorram 
problemas sérios, que podem afetar o sistema como um todo e, por isto, 
deve-se gastar tempo nesta etapa para que, depois, não seja necessário 
tempo redobrado para a correção e customização.
No segundo tópico, daremos continuidade à modelagem; agora, partire-
mos da análise de requisitos e realizaremos um passo a passo para a elaboração 
do diagrama de classes, no tocante à visão do analista/engenheiro de software.
No terceiro tópico, com toda essa modelagem em mãos, daremos iní-
cio à nossa implementação do software, contudo será necessário rever a 
modelagem, de forma que possamos colocar, na visão do desenvolvedor, 
o diagrama de classe, que possuirá alguns atributos e algumas operações 
diferentes de modelagem, na visão do analista/engenheiro.
Após esta análise, poderemos dar início, de fato, à codificação. Esta será 
realizada em Java, utilizando todos os conhecimentos da linguagem em si, 
como a implementação dos pilares da orientação a objetos (encapsulamento, 
herança, polimorfismo e abstração). Os dados serão armazenados em arrays 
dinâmicos, e o sistema conterá um menu de acesso às operações da clínica.
U
N
ID
A
D
E
 5
152
1 ESTUDO DE CASO
Neste estudo de caso, mostraremos um novo documento de requisitos, agora, de 
um laboratório de análises clínicas. Com base nesse documento, elaboraremos o 
diagrama de classes, mas, desta vez, faremos tudo passo a passo.
Antes de começarmos a ler o documento de requisitos, gostaríamos que você 
imaginasse que foi ao médico, por exemplo, a um clínico geral. Para te dar um 
diagnóstico preciso e correto, esse médico pediu que você fizesse uma série de 
exames, por exemplo: hemograma, glicemia, creatinina, triglicerídeos e urocultu-
ra. Ele anotou esta lista em um pedido de exames, e você, de posse deste pedido, 
foi ao laboratório de análises clínicas São João, a fim de fazer os exames. É neste 
momento que começa o nosso documento de requisitos.
Documento de requisitos – Laboratório de análises 
clínicas
O laboratório de análises clínicas São João deseja informatizar as suas atividades, 
pois, hoje, não há controle do histórico de exames de cada paciente e gasta-se mui-
to tempo com atividades que poderiam ser feitas por um sistema informatizado.
Hoje, o laboratório funciona da seguinte forma:
U
N
IC
E
S
U
M
A
R
153
 ■ O paciente (você) chega ao laboratório com o pedido dos exames (preen-
chido pelo médico, o clínico geral que você acabou de consultar).
 ■ Se for a primeira vez que o paciente fará exames, é preenchida uma ficha 
de cadastro com os seguintes dados: nome, endereço, cidade, UF, CEP, 
telefone, data de nascimento, RG e CPF.
 ■ A recepcionista (a moça que te atendeu quando você chegou ao labora-
tório) preenche uma ficha com o nome do paciente, do convênio e dos 
exames que o paciente fará, além da data e do horário de realização de 
cada um. No final da ficha, é anotada a data em que os exames estarão 
prontos. A primeiravia dessa ficha é entregue ao paciente, ou seja, a você.
 ■ O resultado do exame é colocado no envelope para posterior retirada 
pelo paciente.
O laboratório deseja que o novo sistema possa fornecer informações rápidas, preci-
sas e seguras a fim de melhorar as suas atividades administrativas e o atendimento 
aos seus pacientes. Dessa forma, você permanecerá bem menos tempo no labo-
ratório, pois os processos estarão automatizados. Para tanto, o novo sistema deve:
 ■ Permitir o cadastro dos pacientes do laboratório, com todos os dados 
preenchidos na ficha. Este cadastro será realizado pelas recepcionistas.
 ■ Permitir o cadastro dos exames que o laboratório pode realizar. Cada exa-
me pertence a um grupo, por exemplo, o exame hemograma pertence ao 
grupo sangue. Além disso, para cada exame, é preciso saber o seu código, 
a descrição, o valor e os procedimentos para a sua realização. Por exemplo, 
para o hemograma, o paciente deve estar em jejum. Esse cadastro será 
realizado pelos bioquímicos.
 ■ Permitir o cadastro dos pedidos de exames dos pacientes. É necessário 
saber os nomes do paciente, do médico que está solicitando os exames e 
do convênio que o paciente utilizará para esse pedido e, também, o valor 
dos exames, a data e o horário da realização deles e dos seus resultados. 
Atenção: cada exame pode ser realizado em datas e horários diferentes. 
Lembre-se de que o médico pode solicitar mais de um exame em cada 
pedido (no seu caso, solicitou cinco). Esse cadastro será realizado pelas 
recepcionistas.
 ■ Emitir a ficha do paciente, a qual contém todos os dados cadastrados. Este 
relatório será solicitado e recebido tanto pelas recepcionistas quanto pelo 
departamento administrativo do laboratório.
U
N
ID
A
D
E
 5
154
Levantamento e Análise de Requisitos
Uma das primeiras fases de um processo de desenvolvimento de software consiste no 
Levantamento de Requisitos. As outras etapas, sugeridas por muitos autores, são: Análise 
de Requisitos, Projeto, que se constitui na principal fase da modelagem, Codificação, Tes-
tes e Implantação. Dependendo do método/processo adotado, essas etapas ganham, por 
vezes, nomenclaturas diferentes. As etapas de levantamento e análise de requisitos tra-
balham com o domínio do problema e tentam determinar “o que” o software deve fazer, 
e se é realmente possível desenvolver o software solicitado. Na etapa de levantamento de 
requisitos, o engenheiro de software busca compreender as necessidades do usuário e o 
que ele deseja que o sistema a ser desenvolvido realize. Isso é feito, sobretudo, por meio 
de entrevistas, nas quais o engenheiro tenta compreender como funciona, atualmente, o 
processo a ser informatizado, e quais serviços o cliente precisa que o software forneça.
Fonte: Guedes (2011, p. 22).
conceituando
A grande questão é: como saber se as necessidades dos usuários foram realmente bem 
compreendidas?
(Gilleanes T. A. Guedes)
pensando juntos
 ■ Emitir relatório com todos os exames que o laboratório realiza, com o 
código, a descrição, os procedimentos e o valor de cada um, agrupados por 
grupo de exame. Devem ser impressos, nesse relatório, o código e a descri-
ção do grupo. O relatório será solicitado e recebido pelas recepcionistas.
 ■ Emitir o pedido do exame em três vias, com todos os dados do pedido do 
exame. O relatório será emitido pela recepcionista, e a primeira via será 
entregue ao paciente (comprovante da entrega do exame), a segunda via, 
ao departamento de faturamento (para a cobrança dos exames dos con-
vênios), e a terceira via, aos bioquímicos (para a realização dos exames).
 ■ Emitir relatório com os resultados dos exames por pedido, com o nome 
do paciente, a data e o horário do exame (da sua realização), o nome do 
médico que solicitou o procedimento, o nome do convênio e o resultado 
de cada exame realizado, caso tenha sido mais de um. O relatório será 
solicitado pela recepcionista e entregue ao paciente (não é necessário que 
a recepcionista fique com esse relatório).
U
N
IC
E
S
U
M
A
R
155
2 
PASSO A PASSO PARA A
ELABORAÇÃO DO 
DIAGRAMA 
de Classes
1. Lembre-se que os relatórios não serão a classe por si só, mas, para emitir 
cada relatório, utilizaremos diversas classes. Uma dica: se o diagrama pos-
sui um caso de uso de cadastro, certamente, precisará de uma classe para 
armazenar os dados que serão cadastrados neste caso de uso. Seguindo 
este raciocínio, teríamos as seguintes classes:
a) Paciente.
b) Exame.
c) Pedido de exame.
d) Resultado de exame.
e) Médicos.
f) Convênios.
g) Cidades.
h) UFs.
i) Grupos de exames.
2. Agora, para cada uma das classes listadas, relacione os possíveis atri-
butos de cada uma delas. A maioria desses atributos já aparece descrita 
no documento de requisitos. Nunca se esqueça de voltar ao documento 
sempre que tiver dúvidas.
a) Paciente: código, nome, endereço, CEP, cidade, UF, telefone, data de 
nascimento, RG e CPF.
U
N
ID
A
D
E
 5
156
b) Exame: código, descrição, valor, procedimentos e grupo ao qual 
pertence o exame.
c) Pedido de exame: código, nome do paciente, do médico e do convênio, no-
mes dos exames que serão realizados, data e hora da realização de cada um, 
data e hora em que cada exame ficará pronto, bem como o valor de cada.
d) Resultado de exame: descrição do resultado (para cada exame do pedido, 
o resultado deverá ser cadastrado).
e) Médicos: CRM, nome (como o documento de requisitos não menciona 
nada sobre os dados dos médicos, colocaremos somente os atributos que 
interessam para o pedido de exame).
f) Convênios: código, nome (como o documento de requisitos não mencio-
na nada sobre os dados dos convênios, colocaremos somente os atributos 
que interessam para o pedido de exame).
g) Cidades: código, nome, DDD (o documento de requisitos não mencio-
nou nada a respeito, mas esses atributos devem constar em qualquer 
classe de cidades).
h) UFs: sigla, nome.
i) Grupos de exames: código, descrição.
j) Desenhar, no diagrama de classes, as classes relacionadas com os seus 
respectivos atributos. Faremos o desenho do diagrama utilizando a ferra-
menta Astah, no mesmo arquivo em que desenhamos o diagrama de casos 
de uso. Assim, ficaremos com os dois diagramas em um único arquivo.
3. Para cada classe desenhada no diagrama, estabeleça o seu relacionamento 
com as demais. Lembre-se dos tipos de relacionamentos que estudamos: 
associação (unária e binária), generalização/especialização, agregação. 
Releia, também, a explicação sobre classes associativas.
4. Depois disso, estabeleça a multiplicidade de cada relacionamento, 
lembrando de eliminar os atributos que podem ser obtidos por meio 
do relacionamento.
5. Primeiro, desenhe o seu diagrama de classes e, depois, compare-o com o 
nosso, apresentado a seguir:
U
N
IC
E
S
U
M
A
R
157
Pedido Exame
- codigo : int
Médico
- CRM : int
- nome : int Convênio
- codigo : int
- nome : int
Cidade
- codigo : int
- nome : int
- DDD : int
UF
- sigla : int
- nome : int
Grupo Exame
- codigo : int
- descricao : int
Paciente
- codigo : int
- nome : int
- endereco : int
- CEP : int
- telefone : int
- data_nascimento : int
- RG : int
- CPF : int
Exame-Pedido Exame
- data_realizacao_exame : int
- hora_realizacao_exame : int
- data_pronto : int
- hora_pronto : int
- resultado : int
- valor : int
Exame
- codigo : int
- descricao: int
- valor : int
- procedimentos : int
1..*
1..*
1..*
1..*
0..*
0..*
0..*
0..*
Exame-Pedido Exame
 Figura 1 - Diagrama de classes do laboratório de análises clínicas / Fonte: os autores.
Seguem alguns esclarecimentos sobre o diagrama representado na Figura 1:
1. Em um pedido de exame, pode estar relacionado, somente, um paciente, 
um médico e um convênio (no diagrama, não aparece a multiplicidade 
1, por ser o valor default de um relacionamento).
2. Um pedido de exame pode estar relacionado a um ou a vários exames (no 
caso desse documento derequisitos, a cinco deles).
3. Note que os atributos data_realizacao_exame, hora_realizacao_exame, 
data_pronto, hora_pronto, resultado e valor estão armazenados na classe 
associativa, que foi originada do relacionamento muitos para muitos entre 
pedido de exame e exame. Isto se deve ao fato de que, para cada exame, es-
U
N
ID
A
D
E
 5
158
ses atributos podem ser diferentes. Por exemplo: se o atributo data_pronto 
tivesse sido armazenado na classe pedido_exame, seria possível cadastrar, 
somente, uma data em que os exames ficariam prontos. Todavia, na rea-
lidade, não é isto o que acontece, ou seja, em uma lista de exames que o 
paciente precisa realizar, pode-se ter exames que ficam prontos em dois 
dias e os que ficam prontos em cinco.
4. Veja que não foi criada uma classe resultado_exame, pois, como é, so-
mente, uma descrição, decidiu-se armazená-la na classe associativa Exa-
me-Pedido Exame.
5. Note, também, que, na classe Pedido Exame, não aparece o nome do pa-
ciente, assim como relacionamos no item 2 deste passo a passo. Isto por-
que o nome será obtido por meio do relacionamento de Pedido Exame 
com paciente. Não desenhamos o atributo-chave de paciente na classe 
Pedido Exame, mas ele está lá, ou seja, por meio dele é que buscaremos o 
nome do paciente na classe Paciente, quando precisarmos.
6. Em vez de termos utilizado o recurso da classe associativa, poderíamos ter 
usado o relacionamento de agregação. Veja como ficaria (serão mostradas, 
somente, algumas classes; as demais não foram mostradas, pois ficariam 
iguais ao diagrama já apresentado):
Figura 2 - Diagrama de classes associativas / Fonte: os autores.
Pedido Exame
- codigo : int
Grupo Exame
- codigo : int
- descricao : int
Exame-Pedido Exame
- data_realizacao_exame : int
- hora_realizacao_exame : int
- data_pronto : int
- hora_pronto : int
- resultado : int
- valor : int
Exame
- codigo : int
- descricao: int
- valor : int
- procedimentos : int
1..*
1..*
1..*
0..*
0..*
0..*
U
N
IC
E
S
U
M
A
R
159
3 
IMPLEMENTAÇÃO DO 
SOFTWARE
Agora que já temos uma modelagem preliminar do diagrama de classe do la-
boratório de análises clínicas São João, daremos início ao desenvolvimento da 
implementação na linguagem Java.
Primeiro, criaremos um projeto no NetBeans chamado AnalisesCli-
nicas. Inicialmente, desmarque o campo Criar Classe Principal. 
Figura 3 - Criando o projeto AnalisesClinicas / Fonte: os autores.
U
N
ID
A
D
E
 5
160
Em seguida, criaremos um paco-
te com o nome de desenvol-
vimento, com o objetivo de 
separação de códigos.
Após a criação do projeto Anali-
sesClinicas e do pacote desen-
volvimento, daremos início ao de-
senvolvimento das nossas classes. A primeira classe a ser criada no sistema será a 
Paciente, contudo analisaremos as classes que completam o cadastro do paciente e 
as remodelaremos na visão do desenvolvedor, como na figura a seguir.
Figura 5 - Classe para o cadastro do paciente / Fonte: os autores.
Note que, nas classes Paciente, Cidade e Uf, todos os seus respectivos 
atributos possuem a visibilidade private, e os tipos dos dados estão como inteiro. 
Primeiramente, alteraremos os tipos dos atributos de acordo com a necessidade 
do atributo. Na sequência, serão implementados todos os métodos modificadores 
(setters e getters) de todas as classes para garantir o encapsulamento dos atributos. 
Figura 4 - Criando o pacote / Fonte: os autores.
Cidade
- codigo : int
- nome : int
- DDD : int
UF
- sigla : int
- nome : int
Paciente
- codigo : int
- nome : int
- endereco : int
- CEP : int
- telefone : int
- data_nascimento : int
- RG : int
- CPF : int
1..*
0..*
U
N
IC
E
S
U
M
A
R
161
Além desses métodos, deveremos criar outros de acordo com a necessidade do 
estudo de caso, sendo eles:
Na classe Paciente, cidade e UF:
 ■ Para garantir “Permitir o cadastro dos pacientes do 
laboratório, com todos os dados preenchidos na 
ficha de cadastro." Deveremos criar um método que armazene 
os seus referidos campos.
 ■ Para garantir “Emitir a ficha do paciente, a qual con-
tém todos os dados cadastrados. Esse relatório 
será solicitado e recebido tanto pelas recep-
cionistas quanto pelo departamento administra-
tivo do laboratório.”, deveremos criar um método que liste 
todos os referidos campos.
 ■ Lista Paciente, que será utilizado quando solicitar um exame.
Note, ainda, que a classe Paciente possui um relacionamento (1..*) com a classe 
cidade. Esse relacionamento pode ser lido e interpretado da seguinte forma:
Um paciente habita em uma cidade e, em uma cidade, habitam diversos pacientes.
A classe Cidade, possui relacionamento (0..*) com a classe UF, neste caso, 
criaremos um novo atributo, com o nome de Uf, na classe Cidade.
Uma cidade possui um UF e, em uma UF, podem ter zero ou mais cidades.
Note que as classes Paciente e Cidade não possuem um atributo que expli-
cita a relação entre as classes, sendo assim, para que seja possível realizar a mul-
tiplicidade entre as classes, criaremos um novo atributo na classe Paciente, 
com o nome de cidade, e na classe Cidade, com o nome de UF. Como esses 
atributos receberão a ligação com as outras classes, estas, por sua vez, serão do 
tipo da sua respectiva classe, ou seja, o campo cidade, da classe Paciente, 
ficará como cidade: Cidade, e o atributo UF, da classe UF, será colocado: 
uf: UF. Confira a figura a seguir, com todas as referidas alterações.
U
N
ID
A
D
E
 5
162
Figura 6 - Alterações das classes: Paciente, Cidade, UF / Fonte: os autores.
Agora que já remodelamos uma parte do diagrama de classe, codificaremos as 
classes. Para isso, no pacote de desenvolvimento, crie as classes Java para Paciente, 
Cidade e UF, de forma que fique com a seguinte programação: 
Na classe Paciente:
package desenvolvimento;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;
public class Paciente {
 private int codigo;
 private String nome;
 private String endereco;
 private String CEP;
 private String telefone;
 private Date dataNascimento;
 private String RG;
Cidade
- codigo : int
- DDD : String
- UF : UF
+ cadastrar() : void
+ imprimirCidade() : void
+ setters() : void
+ getters() : void
UF
- sigla : String
- nome : String
+ cadastrar() : void
+ imprimirUf() : void
Paciente
- codico : int
- nome : int
- endereco : int
- CEP : int
- telefone : int
- data_nascimento : int
- RG : int
- CPF : int
+ cadastrar() : void
+ listarPaciente() : void
+ imprimirPaciente() : void
+ setters() : void
+ getters() : void
0..*
1..*
1
1
U
N
IC
E
S
U
M
A
R
163
 private String CPF;
 private Cidade cidade = new Cidade();
 
 public int getCodigo(){
 return codigo;
 }
 public void setCodigo(int codigo) {
 this.codigo = codigo;
 }
 public String getNome() {
 return nome;
 }
 public void setNome(String nome) {
 this.nome = nome;
 }
 public String getEndereco() {
 return endereco;
 }
 public void setEndereco(String endereco) {
 this.endereco = endereco;
 }
 public String getCEP() {
 return CEP;
 }
 public void setCEP(String CEP) {
 this.CEP = CEP;
 }
 public String getTelefone() {
 return telefone;
 }
 public void setTelefone(String telefone) {
 this.telefone = telefone;
 }
 public Date getDataNascimento() {
 return dataNascimento;
 }
U
N
ID
A
D
E
 5
164
 public void setDataNascimento(Date dataNascimento) {
 this.dataNascimento = dataNascimento;
 }
 public String getRG() {
 return RG;
 }
 public void setRG(String RG) {
 this.RG = RG;
 }
 public String getCPF() {
 return CPF;
 }
 public void setCPF(String CPF) {
 this.CPF = CPF;
 }
 public Cidade getCidade() {
 return cidade;
 }
 public void setCidade(Cidade cidade) {
 this.cidade = cidade;
 }
 public void cadastrar() throws ParseException{
 Scanner tec = new Scanner(System.in);
 System.out.println("Informe os dados do Paciente");
 System.out.print("Nome: ");
 this.setNome(tec.nextLine());
 System.out.print("Endereço: ");
 this.setEndereco(tec.nextLine());
 System.out.print("CEP: ");
 this.setCEP(tec.nextLine());
 System.out.print("Telefone: ");
 this.setTelefone(tec.nextLine());
 System.out.print("Data de Nascimento Ex: [02/12/1982]:");
 String dataRecebida = tec.nextLine();
U
N
IC
E
S
U
M
A
R
165
 SimpleDateFormat df = new SimpleDateFormat("dd/
MM/yyyy");
 Date dt = df.parse(dataRecebida);
 this.setDataNascimento(dt);
 
 System.out.print("RG: ");
 this.setRG(tec.nextLine());
 System.out.print("CPF: ");
 this.setCPF(tec.nextLine());cidade.cadastra();
 }
 public void imprimirPaciente(){
 SimpleDateFormat formataData= new SimpleDate-
Format("dd/MM/yyyy");
 String stringData = formataData.format(this.ge-
tDataNascimento());
 System.out.println("Paciente: "+this.getNome());
 System.out.println("Endereço: "+this.getEndere-
co());
 System.out.println("CEP: "+this.getCEP());
 System.out.println("Telefone: "+this.getTelefo-
ne());
 
 System.out.println("Data de Nascimento: "+string-
Data);
 System.out.println("RG: "+this.getRG());
 System.out.println("CPF: "+this.getCPF());
 cidade.imprimirCidade(); 
 } 
 public void listarPaciente(){
 System.out.print(" | " +this.getCPF());
 System.out.print(" | " +this.getNome()); 
 }
}
U
N
ID
A
D
E
 5
166
Explicando o código, temos que, na classe Paciente, foi necessário realizar a im-
portação de quatro bibliotecas que serão utilizadas para o tratamento de exceção, 
conversão e formatação de datas e, também, de entrada dos campos, sendo elas: 
import java.text.ParseException; import java.text.SimpleDateFormat; import 
java.util.Date; import java.util.Scanner; respectivamente. 
Para garantir a relação do Paciente com a cidade, foi necessário declarar o campo 
cidade do tipo Cidade - private Cidade cidade = new Ci-
dade();. Neste campo, será instanciado um objeto da classe Cidade, que, no caso, 
armazenará os dados da cidade do Paciente. E, por fim, foram implementados os mé-
todos cadastrar(), imprimirPaciente(), listarPaciente() 
e, para garantir o encapsulamento, foram implementados os métodos modificadores. 
Continuando na classe Paciente, note que, no método cadastrar(), 
estamos trabalhando com o tipo Date para o atributo dataNascimento. 
Neste caso, primeiramente, fazemos a leitura de uma string e armazenamos em 
uma variável “dataRecebida” String dataRecebida = tec.nextLine();. 
Posteriormente, formatamos a dataRecebida por intermédio da classe Sim-
pleDataFormat SimpleDateFormat df = new SimpleDate-
Format(“dd/MM/yyyy”); e, por fim, convertemos a string em dataRe-
cebida pelo Date dt = df.parse(dataRecebida).
Na classe Cidade:
package desenvolvimento;
import java.util.Scanner;
public class Cidade {
 private String nome, ddd;
 private Uf uf = new Uf();
 
 public String getDdd() {
 return ddd;
 }
 public void setDdd(String ddd) {
 this.ddd = ddd;
 }
U
N
IC
E
S
U
M
A
R
167
 public Uf getUf() {
 return uf;
 }
 public void setUf(Uf uf) {
 this.uf = uf;
 }
 
 public String getNome() {
 return nome;
 }
 public void setNome(String nome) {
 this.nome = nome;
 }
 
 public void cadastrar(){
 Scanner tec = new Scanner(System.in);
 System.out.print("Cidade:");
 this.setNome(tec.nextLine());
 System.out.print("DDD: ");
 this.setDdd(tec.nextLine());
 uf.cadastra();
 }
 
 public void imprimirCidade(){
 System.out.println("Cidade: "+this.getNome());
 System.out.println("DDD: "+this.getDdd());
 uf.imprimirUf();
 }
}
Explicando o código, temos que, na classe Cidade, foi necessário realizar a im-
portação de, apenas, uma biblioteca, que será utilizada para a entrada dos campos: 
import java.util.Scanner. 
U
N
ID
A
D
E
 5
168
Para garantir a relação da cidade com o UF, foi necessário declarar o campo 
uf do tipo Uf - private Uf uf = new Uf();. Neste campo, será 
instanciado um objeto da classe UF, que, no caso, armazenará os dados do estado. 
E, por fim, foram implementados os métodos cadastrar(), imprimir-
Cidade(), listarCidade() e, para garantir o encapsulamento, foram 
implementados os métodos modificadores. 
Na classe UF:
package desenvolvimento;
import java.util.Scanner;
public class Uf {
 private String nome;
 private String sigla;
 public String getNome() {
 return nome;
 }
 public void setNome(String nome) {
 this.nome = nome;
 }
 public String getSigla() {
 return sigla;
 }
 public void setSigla(String sigla) {
 this.sigla = sigla;
 }
 
 public void cadastrar(){
 Scanner tec = new Scanner(System.in);
U
N
IC
E
S
U
M
A
R
169
 System.out.print("Estado: ");
 this.setNome(tec.nextLine());
 System.out.print("Sigla: ");
 this.setSigla(tec.nextLine());
 }
 
 public void imprimirUf(){
 System.out.println("Estado: "+this.getNome());
 System.out.println("Sigla: "+this.getSigla());
 } 
}
Agora, analisaremos a parte da modelagem que trata do pedido de exame. Confira 
o recorte a seguir:
Figura 7 - Recorte do pedido de exame / Fonte: os autores.
Note que a classe Paciente foi alterada, agora, alteraremos as classes Médico, Con-
vênio e Pedido Exame. Na classe Médico, alteraremos o tipo do atributo nome e 
incluiremos os métodos para cadastro e impressão, além dos métodos modifica-
dores. O mesmo ocorrerá na classe Convênio e na classe PedidoExame. Confira 
a modelagem atualizada.
Pedido Exame
- codigo : int
Médico
- CRM : int
- nome : int Convênio
- codigo : int
- nome : int
Paciente
- codigo : int
- nome : int
- endereco : int
- CEP : int
- telefone : int
- data_nascimento : int
- RG : int
- CPF : int
1..*
1..* 0..*
0..*
0..*
U
N
ID
A
D
E
 5
170
Figura 8 - Alterações das classes: Médico, Convênio, Pedido de Exame / Fonte: os autores.
Agora que já remodelamos uma parte do diagrama de classe, codificaremos as 
classes. Para isso, no pacote de desenvolvimento, crie as classes Java para Medico, 
Convenio e PedidoExame, de forma que fique com a seguinte programação.
A classe Convênio:
package desenvolvimento;
import java.util.Scanner;
public class Convenio {
 private int codigo;
 private String nome;
 public int getCodigo() {
 return codigo;
 }
 public void setCodigo(int codigo) {
Paciente
- codigo : int
- nome : String
- dataNascimento : Date
- telefone : String
- RG : String
- CPF : String
- endereco : String
- cidade : Cidade
- CEP : String
+ cadastrar() : void
+ listarPaciente() : void
+ imprimirPaciente() : void
+ setters() : void
+ getters() : void
PedidoExame
- codigo : int
- paciente : Paciente
- medico : Medico
- convenio : Convenio
+ cadastrar() : void
+ imprimirPedido() : void
+ setters() : void
+ getters() : void
Médico
- CRM : int
- nome : String
+ cadastrar() : void
+ imprimirMedico() : void
+ listarMedico() : void
+ setters() : void
+ getters() : void
Médico
- codigo : int
- nome : String
+ cadastrar() : void
+ imprimirConvenio() : void
+ listarConvenio() : void
+ setters() : void
+ getters() : void
1
1 1
0..* 0..* 0..*
U
N
IC
E
S
U
M
A
R
171
 this.codigo = codigo;
 }
 public String getNome() {
 return nome;
 }
 public void setNome(String nome) {
 this.nome = nome;
 } 
 public void cadastrar(){
 Scanner cad = new Scanner(System.in);
 System.out.print("Convênio: ");
 this.setNome(cad.nextLine());
 }
 public void imprimirConvenio(){System.out.println("Convênio: "+this.getNo-
me());
 }
}
Explicando o código, temos que, na classe Convenio, foi necessário realizar 
a importação de apenas uma biblioteca, que será utilizada para a entrada dos 
campos: import java.util.Scanner. A classe possui os métodos de 
cadastro e impressão de convênios.
A classe Médico:
package desenvolvimento;
import java.util.Scanner;
public class Medico {
 private int CRM;
 private String nome;
 public int getCRM() {
 return CRM;
 }
 public void setCRM(int CRM) {
U
N
ID
A
D
E
 5
172
 this.CRM = CRM;
 }
 public String getNome() {
 return nome;
 }
 public void setNome(String nome) {
 this.nome = nome;
 } 
 public void cadastrar(){
 Scanner cad = new Scanner(System.in);
 System.out.print("Nome: ");
 this.setNome(cad.nextLine());
 System.out.print("CRM: ");
 this.setCRM(cad.nextInt());
 }
 public void imprimirMedico(){
 System.out.println("Médico: "+this.getNome());
 System.out.println("CRM: "+this.getCRM());
 }
}
Explicando o código, temos que, na classe Medico, foi necessário realizar a importação de 
apenas uma biblioteca, que será utilizada para a entrada dos campos: import java.
util.Scanner. A classe possui os métodos de cadastro e impressão de convênios.
A classe PedidoExame:
package desenvolvimento;
import static desenvolvimento.Programa.c;
import static desenvolvimento.Programa.m;
import static desenvolvimento.Programa.p;
import static desenvolvimento.Programa.contC;
import static desenvolvimento.Programa.contM;
import static desenvolvimento.Programa.contP;
import java.util.Scanner;
U
N
IC
E
S
U
M
A
R
173
public class PedidoExame {
private int codigo;
private Paciente paciente = new Paciente();
private Medico medico = new Medico();
private Convenio convenio = new Convenio();
 
public int getCodigo() {
return codigo;
}
public void setCodigo(int codigo) {
this.codigo = codigo;
}
public Paciente getPaciente() {
return paciente;
}
public void setPaciente(Paciente paciente) {
this.paciente = paciente;
}
public Medico getMedico() {
return medico;
}
public void setMedico(Medico medico) {
this.medico = medico;
}
public Convenio getConvenio() {
return convenio;
}
public void setConvenio(Convenio convenio) {
this.convenio = convenio;
} 
public void cadastrar(){
Scanner cad = new Scanner(System.in);
int codPaciente, codMedico, codConvenio;
System.out.println("----------------------");
System.out.println("Relação de Pacientes");
System.out.println("Código | CPF | Nome");
U
N
ID
A
D
E
 5
174
for(int i = 0; i < contP; i++){
System.out.print(" "+i);
p[i].listarPaciente();
System.out.println();
}
System.out.println("Escolha um Paciente");
codPaciente = cad.nextInt();
this.setPaciente(p[codPaciente]);
cad.nextLine();
 
System.out.println("--------------------");
System.out.println("Relação de Médicos");
System.out.println("Código | CRM | Nome");
for(int i = 0; i < contM; i++){
System.out.print(" "+i);
m[i].listarMedico();
System.out.println();
}
System.out.println("Escolha um Médico");
codMedico = cad.nextInt();
this.setMedico(m[codMedico]);
cad.nextLine();
 
System.out.println("-------------------------");
System.out.println("Relação de Convênio");
System.out.println("Código | Nome");
for(int i = 0; i < contC; i++){
System.out.print(" "+i);
c[i].imprimirConvenio();
System.out.println();
}
System.out.println("Escolha um convênio");
codConvenio = cad.nextInt();
this.setConvenio(c[codConvenio]);
cad.nextLine();
}
U
N
IC
E
S
U
M
A
R
175
public void imprimirPedidoExame(){
System.out.println("Médico: "+this.getMedi-
co().getNome());
System.out.println("Convênio: "+this.getConve-
nio().getNome());
System.out.println("Paciente: "+this.getPa-
ciente().getNome());
}
}
Como a classe PedidoExame() possui os relacionamentos com as classes 
Convenio, Medico e Paciente, classes estas já construídas em seu material, faz-se 
necessário importar os registros de cada classe para abrir o pedido de exame. Os 
arrays estão armazenadas na classe Programa, que será a nossa classe principal 
do sistema, a qual, até o presente momento não desenvolvemos (Ver a classe 
Programa). Confira, a seguir, a importação dos arrays.
import static desenvolvimento.Programa.c; 
import static desenvolvimento.Programa.m; 
import static desenvolvimento.Programa.p;
Além de importar os arrays, é necessário importar a última posição de cada um, 
o que indicará quantos registros temos em cada array.
import static desenvolvimento.Programa.contC;
import static desenvolvimento.Programa.contM;
import static desenvolvimento.Programa.contP;
Continuando a explicação da nossa classe, veja que declaramos os objetos pa-
ciente, médico e convênio para que possamos garantir os relacionamentos dessa 
classe com as demais.
private Paciente paciente = new Paciente();
private Medico medico = new Medico();
private Convenio convenio = new Convenio();
U
N
ID
A
D
E
 5
176
Na sequência, foram desenvolvidos os métodos modificadores, que garantem o 
encapsulamento dos atributos.
O método cadastrar é o cerne dessa classe, é nele que os relacionamentos 
acontecem. Veja que, de início, declaramos três variáveis do tipo inteiro (int 
codPaciente, codMedico, codConvenio;), variáveis estas que 
permitirão ao usuário informar o registro e, posteriormente, armazenar nos atri-
butos de relacionamento da classe.
O primeiro bloco de códigos do método cadastrar lista e todos os pacientes 
estão armazenados no array p[]por meio do método listarPaciente(). 
Após listar todos os pacientes, o usuário digitará a posição do array onde se en-
contra o paciente e, na sequência, armazenará o objeto com a posição do paciente 
selecionado. 
System.out.println(“Relação de Pacientes”);
System.out.println(“Código | CPF | Nome”);
 for(int i = 0; i < contP; i++){
 System.out.print(“ “+i);
 p[i].listarPaciente();
 System.out.println();
 }
 System.out.println(“Escolha um Paciente”);
 codPaciente = cad.nextInt();
 this.setPaciente(p[codPaciente]);
 cad.nextLine();
No segundo e no terceiro bloco deste método, ocorrem a listagem, a seleção e o 
armazenamento do objeto, além da sua respectiva posição selecionada das classes 
médico e convenio, respectivamente.
Após esta parte inicial, será chamada a classe associativa, que armazenará os 
exames do pedido do paciente.
Agora, analisaremos a parte da modelagem que trata do grupo do exame e 
do exame. Confira o recorte a seguir:
U
N
IC
E
S
U
M
A
R
177
Figura 9 - Recorte do grupo de exame / Fonte: os autores.
Na classe Exame, alteraremos o tipo dos atributos e incluiremos os métodos para 
cadastro, listagem e impressão, além dos métodos modificadores. O mesmo ocor-
rerá na classe GrupoConvenio. Confira a modelagem atualizada:
Figura 10 - Alterações das classes Exame e GrupoExame / Fonte: os autores.
Agora, codificaremos as classes, já que remodelamos uma parte do diagrama 
delas. Para isso, no pacote de desenvolvimento, crie as classes Java para Exame e 
GrupoExame, de forma que fiquem com a seguinte programação:
A classe GrupoExame
package desenvolvimento;
import java.util.Scanner;
public class GrupoExame {
Grupo Exame
- codigo : int
- descricao : int
Exame
- codigo : int
- descricao: int
- valor : int
- procedimentos : int
1..*
Exame
- codigo : int
- descricao : String
- valor : double
- procedimentos : String
- grupoExame : GrupoExame
+ cadastrar() : void
+ imprimirExame() : void
+ listarExame() : void
+ setters() : void
+ getters() : void
GrupoExame
- codigo : int
- descricao : String
+ cadastrar() : void
+ imprimirGrupoExame() : void
+ setters() : void
+ getters() : void
1..* 1
U
N
ID
A
D
E
 5
178
 private int codigo;
 private String Descricao;
 public int getCodigo() {
 return codigo;
 }
 public void setCodigo(int codigo){
 this.codigo = codigo;
 }
 public String getDescricao() {
 return Descricao;
 }
 public void setDescricao(String Descricao) {
 this.Descricao = Descricao;
 }
 public void cadastrar(){
 Scanner cad = new Scanner (System.in);
 System.out.print("Código do Grupo: ");
 this.setCodigo(cad.nextInt());
 cad.nextLine();
 System.out.print("Grupo do Exame: ");
 this.setDescricao(cad.nextLine());
 }
 public void imprimirGrupoExame(){
 System.out.println("Codigo: "+this.getCodigo());
 System.out.println("Grupo do Exame: "+this.getDescricao());
 System.out.println("--------------------");
 }
 public void listarGrupoExame(){
 System.out.print(" | "+this.getDescricao());
 }
}
A classe GrupoExame dispensa explicação, uma vez que já é possível o seu 
entendimento. Implementaremos a classe Exame.
U
N
IC
E
S
U
M
A
R
179
package desenvolvimento;
import static desenvolvimento.Programa.contGe;
import static desenvolvimento.Programa.ge;
import java.util.Scanner;
public class Exame {
private int codigo;
private String Descricao;
private double valor;
private String procedimentos;
private GrupoExame grupoExame = new GrupoExame();
public int getCodigo() {
return codigo;
}
public void setCodigo(int codigo) {
this.codigo = codigo;
}
public String getDescricao() {
return Descricao;
}
public void setDescricao(String Descricao) {
this.Descricao = Descricao;
}
public double getValor() {
return valor;
}
public void setValor(double valor) {
this.valor = valor;
} 
public String getProcedimentos() {
return procedimentos;
}
public void setProcedimentos(String procedimentos) {
this.procedimentos = procedimentos;
 }
U
N
ID
A
D
E
 5
180
public GrupoExame getGrupoExame() {
return grupoExame;
} 
public void setGrupoExame(GrupoExame grupoExame) {
this.grupoExame = grupoExame;
} 
public void cadastrar(){
Scanner cad = new Scanner(System.in);
int codGrupoExame;
System.out.println("----------------------");
System.out.println("Relação dos Grupos");
System.out.println("Código | Grupos");
for(int i = 0; i < contGe; i++){
System.out.print(" "+i);
ge[i].listarGrupoExame();
System.out.println();
}
System.out.println("Vincule a um grupo");
codGrupoExame = cad.nextInt();
this.setGrupoExame(ge[codGrupoExame]);
cad.nextLine();
System.out.println("Código: ");
this.setCodigo(cad.nextInt());
cad.nextLine();
 
System.out.println("Exame");
this.setDescricao(cad.nextLine());
System.out.println("Valor");
this.setValor(cad.nextDouble());
cad.nextLine();
System.out.println("Procedimentos");
U
N
IC
E
S
U
M
A
R
181
this.setProcedimentos(cad.nextLine()); 
}
 public void imprimirExame(){
System.out.println("Código.........: "+this.
getCodigo());
System.out.println("Exame..........: "+this.
getDescricao());
System.out.println("Grupo do Exame.: "+this.
getGrupoExame().getDescricao());
System.out.println("Valor..........: "+this.
getValor());
System.out.println("Procedimentos..: "+this.
getProcedimentos());
System.out.println("-------------------");
}
}
Como a classe Exame() possui o relacionamento com a classe GrupoExame, 
faz-se necessário importar os registros de cada classe para possibilitar o relacio-
namento do exame em seu respectivo grupo. O array está armazenado na classe 
Programa, que será a nossa classe principal do sistema (ver a classe Programa). 
Confira, a seguir, a importação do array.
import static desenvolvimento.Programa.ge;
Além de importar o array, é necessário importar a última posição dele, que in-
dicará quantos registros temos.
import static desenvolvimento.Programa.contGe;
Continuando a explicação sobre a nossa classe, vejam que foi declarada a classe 
GrupoExame() para garantir o relacionamento desta com a de Exame.
U
N
ID
A
D
E
 5
182
private GrupoExame grupoExame = new GrupoExame();
Na sequência, foram desenvolvidos os métodos modificadores, que garantem o 
encapsulamento dos atributos.
O método cadastrar é o cerne dessa classe, é nele que os relacionamentos 
acontecem. Veja que, de início, declaramos uma variável do tipo inteiro (int 
codGrupoExame;), variável essa que permitirá ao usuário informar o registro 
e, posteriormente, armazená-lo no atributo de relacionamento da classe.
A primeira parte de código do método Cadastrar lista todos os grupos de 
exames que estão armazenados no array ge[],por meio do método listar-
GrupoExame(). Após listar todos os grupos, o usuário digitará a posição do 
array onde se encontra o grupo e, na sequência, armazena o objeto com a posição 
do grupo selecionado. 
System.out.println("Relação dos Grupos");
System.out.println("Código | Grupos");
 for(int i = 0; i < contGe; i++){
 System.out.print(" "+i);
 ge[i].listarGrupoExame();
 System.out.println();
 }
System.out.println("Vincule a um grupo");
codGrupoExame = cad.nextInt();
this.setGrupoExame(ge[codGrupoExame]);
cad.nextLine();
Confira a modelagem completa do estudo de caso da clínica de exames.
U
N
IC
E
S
U
M
A
R
183
Figura 11 - Modelagem final / Fonte: os autores. 
ExamePedidoExame
- dataRealizacaoExame : Date
- horaRealizacaoExame : time
- dataPronto : Date
- horaPronto : time
- resultado : String
- ExamePedido : Exame
1 1
0..*
0..*
0..*
1..* 1
ExamePedidoExame
PedidoExame
- codigo : int
- paciente : Paciente
- medico : Medico
- convenio : Convenio
+ cadastrar() : void
+ imprimirPedido() : void
+ setters() : void
+ getters() : void
Médico
- CRM : int
- nome : String
+ cadastrar() : void
+ imprimirMedico() : void
+ listarMedico() : void
+ setters() : void
+ getters() : void
Exame
- codigo : int
- descricao : String
- valor : double
- procedimentos : String
- grupoExame : GrupoExame
+ cadastrar() : void
+ imprimirExame() : void
+ listarExame() : void
+ setters() : void
+ getters() : void
GrupoExame
- codigo : int
- descricao : String
+ cadastrar() : void
+ imprimirGrupoExame() : void
+ setters() : void
+ getters() : void
Convenio
- codigo : int
- nome : String
+ cadastrar() : void
+ imprimirConvenio() : void
+ listarConvenio() : void
+ setters() : void
+ getters() : void
Paciente
- codigo : int
- nome : String
- dataNascimento : Date
- telefone : String
- RG : String
- CPF : String
- endereco : String
- cidade : Cidade
- CEP : String
+ cadastrar() : void
+ listarPaciente() : void
+ imprimirPaciente() : void
+ setters() : void
+ getters() : void
Cidade
- codigo : int
- DDD : String
- UF : UF
+ cadastrar() : void
+ imprimirCidade() : void
+ setters() : void
+ getters() : void
UF
- sigla : String
- nome : String
+ cadastrar() : void
+ imprimirUf() : void
0..*
1
1..*
1
1
U
N
ID
A
D
E
 5
184
Agora, desenvolveremos a classe ExamePedidoExame, classe essa que reunirá 
as informações dos exames e os seus respectivos dias. O código dela é conhecido, 
dessa forma, deixamos para você a tarefa de analisar o que está sendo realizado 
nela. No geral, o usuário escolhe o exame e realiza a entrada com as datas e as 
horas do exame.
package desenvolvimento;
import static desenvolvimento.Programa.contEx;
import static desenvolvimento.Programa.ex;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;
public class ExamePedidoExame {
private Date dataRealizacaoExame;
private Date dataPronto;
private Exame examePedido = new Exame();
private Date horaRealizacaoExame;
private Date horaPronto;
private String resultado;
public Exame getExamePedido() {
return examePedido;
}
public void setExamePedido(Exame examePedido) {
this.examePedido = examePedido;
}
public Date getDataRealizacaoExame() {
return dataRealizacaoExame;
}
public void setDataRealizacaoExame(Date dataReali-
zacaoExame) {
this.dataRealizacaoExame = dataRealizacaoExame;
}
U
N
IC
E
S
U
M
A
R
185
public Date getDataPronto() {
return dataPronto;
}
publicvoid setDataPronto(Date dataPronto) {
this.dataPronto = dataPronto;
}
public Date getHoraRealizacaoExame() {
return horaRealizacaoExame;
}
public void setHoraRealizacaoExame(Date horaReali-
zacaoExame) {
this.horaRealizacaoExame = horaRealizacaoExame;
}
public Date getHoraPronto() {
return horaPronto;
}
public void setHoraPronto(Date horaPronto) {
this.horaPronto = horaPronto;
}
public String getResultado() {
return resultado;
}
public void setResultado(String resultado) {
this.resultado = resultado;
}
public void cadastrar() throws ParseException{
Scanner cad = new Scanner(System.in);
int codE;
System.out.println("--------------------");
System.out.println("Relação de Exames");
System.out.println("Cód | Descrição | Valor");
for(int i = 0; i < contEx; i++){
System.out.print(" "+i);
U
N
ID
A
D
E
 5
186
ex[i].listarExame();
System.out.println();
}
System.out.println("Escolha um Exame: ");
codE = cad.nextInt();
this.setExamePedido(ex[codE]);
cad.nextLine();
System.out.print("Data Realização exame Ex: [02/12/1982]:");
String dataRealizarExame = cad.nextLine();
SimpleDateFormat sdf1 = new SimpleDateForma-
t("dd/MM/yyyy");
Date dt1 = sdf1.parse(dataRealizarExame);
this.setDataRealizacaoExame(dt1);
System.out.print("Data exame pronto Ex: 
[02/12/1982]: ");
String dataRetirarExame = cad.nextLine();
SimpleDateFormat sdf2 = new SimpleDateForma-
t("dd/MM/yyyy");
Date dt2 = sdf2.parse(dataRetirarExame);
this.setDataPronto(dt2);
System.out.print("Hora Realização exame Ex: 
[10:12]: ");
String horaRealizarExame = cad.nextLine();
SimpleDateFormat sdf3 = new SimpleDateForma-
t("HH:mm");
Date dth1 = sdf3.parse(horaRealizarExame);
this.setHoraRealizacaoExame(dth1);
System.out.print("Hora exame pronto Ex: 
[10:12]: ");
String horaRetirarExame = cad.nextLine();
U
N
IC
E
S
U
M
A
R
187
SimpleDateFormat sdf4 = new SimpleDateForma-
t("HH:mm");
Date dth2 = sdf4.parse(horaRetirarExame);
this.setHoraPronto(dth2);
System.out.print("Valor: "+ this.getValor());
}
public void imprimir(){
SimpleDateFormat formataData= new SimpleDate-
Format("dd/MM/yyyy");
String dataRealizarExame = formataData.forma-
t(this.getDataRealizacaoExame());
System.out.println("Data do Exame: "+dataRea-
lizarExame);
SimpleDateFormat formataHora= new SimpleDate-
Format("HH:mm");
String horaRealizarExame = formataHora.forma-
t(this.getHoraRealizacaoExame());
System.out.println("Horário do Exame: "+hora-
RealizarExame);
String dataRetirarExame = formataData.format(-
this.getDataPronto());
System.out.println("Data para retirar o Exame: 
"+dataRetirarExame);
String stringData13 = formataHora.format(this.
getHoraPronto());
System.out.println("Horário para retirar o 
Exame: "+stringData13);
}
}
U
N
ID
A
D
E
 5
188
Agora, chegou a hora de colocarmos o nosso có-
digo para rodar. No pacote de desenvolvimento, 
crie uma nova classe Java principal e a salve como 
Programa. Confira, na Figura 12, como ficou a 
estrutura de classes do nosso sistema.
package desenvolvimento;
import java.text.ParseException;
import java.util.Scanner;
public class Programa {
static Paciente p[] = new Paciente[10];
static Medico m[] = new Medico[10];
static Convenio c[] = new Convenio[10];
static PedidoExame pe[] = new PedidoExame[10];
static GrupoExame ge[] = new GrupoExame[10];
static Exame ex[] = new Exame[10];
static ExamePedidoExame pexe[] = new ExamePedidoExame[10];
public static int contPe = 0;
public static int contP = 0;
public static int contM = 0;
public static int contC = 0;
public static int contGe = 0;
public static int contEx = 0;
public static int contPexe = 0;
public static void imprimePaciente(){
for(int i = 0; i < contP; i++){
Figura 12 - Estrutura de classes
Fonte: os autores.
U
N
IC
E
S
U
M
A
R
189
System.out.print(i);
p[i].imprimirPaciente();
System.out.println("----------------------");
}
}
public static void imprimeConvenio(){
for(int i = 0; i < contC; i++){
c[i].imprimirConvenio();
System.out.println("----------------------");
}
}
public static void imprimeMedico(){
for(int i = 0; i < contM; i++){
m[i].imprimirMedico();
System.out.println("----------------------");
}
}
public static void imprimePedidoExame(){
for(int i = 0; i < contPe; i++){
pe[i].imprimirPedidoExame();
System.out.println("----------------------");
for(int j = 0; j < contPexe; j++){
pexe[j].imprimir();
System.out.println ("-------------------
---");
}
}
}
public static void imprimeGrupoExame(){
for(int i = 0; i < contGe; i++){
ge[i].imprimirGrupoExame();
System.out.println("----------------------");
}
}
public static void imprimeExame(){
U
N
ID
A
D
E
 5
190
for(int i = 0; i < contEx; i++){
ex[i].imprimirExame();
System.out.println ("------------");
}
}
public static void main(String[] args) throws Par-
seException {
Scanner tec = new Scanner(System.in);
int opcao = 1;
while(opcao!=0){
System.out.println("----------------");
System.out.println("SISTEMA ANALISES CLINICAS");
System.out.println("------------------------");
System.out.println("|PACIENTE [1 - Cadas-
trar] [2 - Listar]|");
System.out.println("|CONVÊNIO [3 - Cadas-
trar] [4 - Listar]|");
System.out.println("|MÉDICO [5 - Cadas-
trar] [6 - Listar]|");
System.out.println("|PEDIDO EXAME [7 - CADAS-
TRAR] [8 - Listar]|");
System.out.println("|EXAME [9 - CADAS-
TRAR] [10 - Listar]|");
System.out.println("|GRUPO EXAME [11 - CADAS-
TRAR] [12 - Listar]|");
System.out.println ("-------------------");
System.out.println("| 0 - Sair |");
System.out.print("Escolha uma opção: ");
opcao = tec.nextInt();
tec.nextLine();
switch(opcao){
case 1:
p[contP] = new Paciente();
p[contP].cadastrar();
U
N
IC
E
S
U
M
A
R
191
contP++;
break;
case 2:
imprimePaciente();
break;
case 3:
c[contC] = new Convenio();
c[contC].cadastrar();
contC++;
break;
case 4:
imprimeConvenio();
break;
case 5:
m[contM] = new Medico();
m[contM].cadastrar();
contM++;
break;
case 6:
imprimeMedico();
break;
case 7:
 
pe[contPe] = new PedidoExame();
pe[contPe].cadastrar();
contPe++;
int resp = 1;
while(resp == 1){
pexe[contPexe] = new ExamePedidoExame();
pexe[contPexe].cadastrar();
contPexe++;
System.out.print("Deseja cadastrar 
outro exame? [1 - Sim][0 - Não]: " );
resp = tec.nextInt();
tec.nextLine();
}
U
N
ID
A
D
E
 5
192
break;
case 8:
imprimePedidoExame();
break;
case 9:
ex[contEx] = new Exame();
ex[contEx].cadastrar();
contEx++;
break;
case 10:
imprimeExame();
break;
case 11:
ge[contGe] = new GrupoExame();
ge[contGe].cadastrar();
contGe++;
break;
case 12:
imprimeGrupoExame();
break;
default:
System.exit(0);
}
}
}
}
Explicando o código do programa principal, temos a instância de cada classe em 
seu respectivo objeto, sendo esse do tipo vetor de modificador static. Depois, a 
declaração dos contadores de cada vetor, também, com modificador static. Em 
seguida, construímos um menu de opções chamando os métodos de cadastro 
que instanciam, em cada posição do vetor, uma nova instância da classe. Depois, 
há a impressão dos dados cadastrados.
U
N
IC
E
S
U
M
A
R
193
CONSIDERAÇÕES FINAIS
Chegamos ao final da nossa última unidade do livro. Nesta, apresentamos a você o 
estudo de caso fictício de uma clínica de exames médicos. Neste estudo, partimos 
da apresentação do problema, fizemos a análise de requisitos, a modelagem UML 
do diagrama de classe e, posteriormente, a implementação do estudo de caso na 
linguagem Java. Porém, como cada analista é único, você pode, depois, remodelar 
as classes, colocar mais propriedades e comportamentos, bem como abstrair mais 
informações, ou seja, remodelar a modelagem apresentada.
A proposta do sistema era realizar o cadastro e a impressão das informações 
do sistema. Dessa forma, deixamos algumas lacunas de melhoria a serem imple-
mentadas no sistema construído.
 ■ A primeira lacuna que pode ser melhorada são os tratamentos de exce-
ções e validações nos campos informados pelo usuário, por exemplo, CPF, 
data e hora, entreoutros campos que, no momento, aceitam quaisquer 
valores por estarem com o tipo String. 
 ■ A segunda lacuna é a implementação de persistência, armazenando os 
dados em um banco de dados relacional, de forma que possam ser gerados 
diversos tipos de relatórios e seja facilitada a entrada de valores. 
 ■ A terceira lacuna é deixar a interface do seus sistema mais robusta, com 
interação homem-máquina mais interessante. Neste caso, pode-se utilizar 
o recurso de interfaces gráficas com o Swing, saindo do modo de console. 
 ■ A quarta lacuna é trocar os arrays simples pela classe ArrayList, que tra-
balha com vetores de forma dinâmica. Esta classe possui diversas funções 
que facilitam e permitem dinamizar as interações no sistema de forma 
mais amigável e robusta.
Estas são algumas das lacunas que deixamos abertas para que você, aluno(a), 
possa resgatá-las nas disciplinas de Programação I e Programação II. Isto, com 
certeza, fará a diferença no mercado de trabalho.
194
na prática
1. Analise a modelagem a seguir. De acordo com ela, implemente as classes e crie uma re-
gra de negócios que não permita aos clientes o saque em valor superior ao seu saldo.
2. Em programas orientados ao objeto, normalmente, existem várias classes em vá-
rios pacotes e elas interagem entre si. Para utilizar outras classes, tanto as criadas 
por você quanto as do próprio Java, muitas vezes, é necessário importá-las com o 
comando import. Considerando estas informações, analise as afirmações a seguir.
I - Se a classe Carro está no pacote “raiz”, a classe Moto está no pacote “veiculos” e 
o pacote “veiculos” está dentro do pacote “raiz”, então, a classe Carro não precisa 
importar a classe Moto para utilizá-la.
II - O comando import não é necessário quando se referencia uma classe do mesmo pacote.
III - Não há a necessidade de utilizar import quando a classe consta no pacote “java.lang”.
É correto o que se afirma em:
a) II, apenas.
b) I e II, apenas.
c) I e III, apenas.
d) II e III, apenas.
e) I, II e III.
3. Ao permitirem que os objetos possuam comportamentos, os métodos os deixam muito 
versáteis e úteis. Um método pode ser chamado por outra classe ou, ainda, chamar 
outro método dentro da mesma classe onde foi declarado. Considerando as chamadas 
de métodos que estejam dentro da mesma classe, analise o trecho de código a seguir:
ContaCorrente
- agencia : int
- conta : int
- cpf : String
- saldo : int
+ depositar(valor : double) : void
+ sacar(valor : double) : void
+ imprimirSaldo() : void
195
na prática
public class Principal {
 public static void main(String[] args) {
 mostrarDados(25, "João");
 }
 public void mostrarDados(int idade, String nome){
 System.out.println("idade:" + idade + "Nome:" + nome;)
 }
}
Considerando o código exposto, pode-se afirmar que:
a) A saída do sistema será: “Idade: 25 Nome: João”. 
b) O método mostrarDados não pode ser chamado pelo método main, pois méto-
dos estáticos não podem chamar outros métodos.
c) O método mostrarDados não pode ser chamado pelo método main, pois méto-
dos estáticos só podem chamar métodos estáticos.
d) O método mostrarDados não pode ser chamado pelo método main, pois o mé-
todo main não pode chamar nenhum outro método.
e) O método mostrarDados não pode ser chamado pelo método main, pois méto-
dos estáticos só podem chamar métodos que não esperam parâmetros.
4. O desenvolvedor Java de determinada empresa deparou-se com a necessidade 
de criar uma classe chamada Pessoa para atender às necessidades de negócio da 
aplicação que ele estava desenvolvendo. Porém, como usava uma biblioteca de 
classes de terceiros, o desenvolvedor notou que já havia uma classe Pessoa criada.
Analisando o estudo de caso exposto, é correto afirmar que, para não haver erros 
no projeto, o programa deve:
a) Criar a classe Pessoa, desde que ela esteja no mesmo pacote da classe Pessoa criada.
b) Criar a classe Pessoa, desde que esteja em um pacote diferente da classe Pessoa 
criada anteriormente.
196
na prática
c) Não poderá criar a classe Pessoa, pois o Java não permite a criação de classes 
com o mesmo nome.
d) Criar a classe Pessoa, porém com o P minúsculo, tornando-se pessoa, pois o Java 
distingue maiúsculas de minúsculas.
e) Criar a classe Pessoa normalmente, pois o compilador Java saberá identificar que 
as classes, apesar de terem o mesmo nome, são diferentes.
5. O trecho de código, a seguir, representa uma classe chamada Pessoa, com as suas 
definições. Temos, ainda, o método main, realizando a chamada ao método telefonar 
da classe Pessoa.
public static void main(String[] args) {
 Pessoa pessoa = new Pessoa ();
 pessoa.telefone = "3377-5654";
 pessoa.telefonar ();
}
public class Pessoa {
 public String nome;
 public int idade;
 public void telefonar () {
 String telefone = "3322-5599";
 System.out.println ("Ligar para" + telefone);
 }
}
Considerando o código exposto, caso ele seja executado do jeito que está, o Java 
lançará algum erro? Se sim, reescreva o código de maneira que possamos chamar 
o método telefonar a partir do método main, porém de maneira que não lance 
mais nenhum erro.
197
aprimore-se
INTRODUÇÃO À TECNOLOGIA DE OBJETOS
Hoje, como a demanda por software novo e mais poderoso está aumentando, cons-
truir softwares de maneira rápida, correta e econômica continua a ser um objetivo 
indefinido. Objetos ou, mais precisamente, as classes de onde os objetos vêm são 
essencialmente componentes reutilizáveis de software. Há objetos data, objetos 
data/hora, objetos áudio, objetos vídeo, objetos automóvel, objetos pessoas etc. 
Quase qualquer substantivo pode ser razoavelmente representado como um ob-
jeto de software em termos dos atributos (por exemplo, nome, cor e tamanho) e 
comportamentos (por exemplo, calcular, mover e comunicar). Grupos de desenvol-
vimento de software podem usar uma abordagem modular de projeto e implemen-
tação orientados a objetos para que sejam muito mais produtivos do que com as 
técnicas anteriormente populares como “programação estruturada” — programas 
orientados a objetos são muitas vezes mais fáceis de entender, corrigir e modificar.
O automóvel como um objeto
Para ajudar a entender objetos e seus conteúdos, vamos começar com uma analogia 
simples. Suponha que você queira guiar um carro e fazê-lo andar mais rápido pisan-
do no pedal acelerador. O que deve acontecer antes que você possa fazer isso? Bem, 
antes de poder dirigir um carro, alguém tem de projetá-lo. Um carro tipicamente 
começa como desenhos de engenharia, semelhantes a plantas que descrevem o 
projeto de uma casa. Esses desenhos incluem o projeto do pedal do acelerador. O 
pedal oculta do motorista os complexos mecanismos que realmente fazem o carro 
ir mais rápido, assim como o pedal de freio “oculta” os mecanismos que diminuem a 
velocidade do carro e a direção “oculta” os mecanismos que mudam a direção dele. 
Isso permite que pessoas com pouco ou nenhum conhecimento sobre como moto-
res, freios e mecanismos de direção funcionam consigam dirigir um carro facilmen-
te. Assim como você não pode cozinhar refeições na planta de uma cozinha, não 
pode dirigir os desenhos de engenharia de um carro. Antes de poder guiar um carro, 
ele deve ser construído a partir dos desenhos de engenharia que o descrevem. Um 
198
aprimore-se
carro pronto tem um pedal de acelerador real para fazê-lo andar mais rápido, mas 
mesmo isso não é suficiente — o carro não acelerará por conta própria (tomara!), 
então o motorista deve pressionar o pedal do acelerador.
Métodos e classes
Vamos usar nosso exemplo do carro para introduzir alguns conceitos fundamentais 
da programação orientada a objetos. Para realizar uma tarefa em um programa é 
necessário um método. O método armazena as declarações do programa que, na 
verdade, executam as tarefas; além disso, ele oculta essas declarações do usuário, 
assim como o pedal do aceleradorde um carro oculta do motorista os mecanismos 
para fazer o veículo ir mais rápido. No Java, criamos uma unidade de programa 
chamada classe para armazenar o conjunto de métodos que executam as tarefas 
dela. Por exemplo, uma classe que representa uma conta bancária poderia conter 
um método para fazer depósitos de dinheiro, outro para fazer saques e um terceiro 
para perguntar qual é o saldo atual. 
Uma classe é similar em termos do conceito aos desenhos de engenharia de um 
carro, que armazenam o projeto de um pedal de acelerador, volante etc.
Instanciação
Assim como alguém tem de fabricar um carro a partir dos desenhos de engenharia 
antes que possa realmente dirigi-lo, você deve construir um objeto de uma classe 
antes que um programa possa executar as tarefas que os métodos da classe defi-
nem. O processo para fazer isso é chamado instanciação. Um objeto é então referi-
do como uma instância da sua classe.
Reutilização
Assim como os desenhos de engenharia de um carro podem ser reutilizados vá-
rias vezes para fabricar muitos carros, você pode reutilizar uma classe muitas vezes 
199
aprimore-se
para construir vários objetos. A reutilização de classes existentes ao construir novas 
classes e programas economiza tempo e esforço. Também ajuda a construir siste-
mas mais confiáveis e eficientes, porque classes e componentes existentes costu-
mam passar por extensos testes, depuração e ajuste de desempenho. Assim como 
a noção das partes intercambiáveis foi crucial para a Revolução Industrial, classes 
reutilizáveis são fundamentais para a revolução de software que foi estimulada pela 
tecnologia de objetos.
Mensagens e chamadas de método
1. Ao dirigir um carro, o ato de pressionar o acelerador envia uma mensagem para 
o veículo realizar uma tarefa — isto é, ir mais rápido. Da mesma forma, você 
envia mensagens para um objeto. Cada mensagem é implementada como uma 
chamada de método que informa a um método do objeto a maneira de realizar 
sua tarefa. Por exemplo, um programa pode chamar o método depósito de um 
objeto conta bancária para aumentar o saldo da conta.
Atributos e variáveis de instância
Um carro, além de ter a capacidade de realizar tarefas, também tem atributos, como 
cor, número de portas, quantidade de gasolina no tanque, velocidade atual e regis-
tro das milhas totais dirigidas (isto é, a leitura do odômetro). Assim como suas ca-
pacidades, os atributos do carro são representados como parte do seu projeto nos 
diagramas de engenharia (que, por exemplo, incluem um odômetro e um medidor 
de combustível). Ao dirigir um carro real, esses atributos são incorporados a ele. 
Cada carro mantém seus próprios atributos. Cada carro sabe a quantidade de gaso-
lina que há no seu tanque, mas desconhece quanto há no tanque de outros carros.
Um objeto, da mesma forma, tem atributos que ele incorpora à medida que é 
usado em um programa. Esses atributos são especificados como parte da classe do 
objeto. Por exemplo, um objeto conta bancária tem um atributo saldo que repre-
senta a quantidade de dinheiro disponível. Cada objeto conta bancária sabe o saldo 
200
aprimore-se
que ele representa, mas não os saldos de outras contas bancárias. Os atributos são 
especificados pelas variáveis de instância da classe.
Encapsulamento e ocultamento de informações
Classes (e seus objetos) encapsulam, isto é, contêm seus atributos e métodos. Os 
atributos e métodos de uma classe (e de seu objeto) estão intimamente relaciona-
dos. Os objetos podem se comunicar entre si, mas eles em geral não sabem como 
outros objetos são implementados — os detalhes de implementação permanecem 
ocultos dentro dos próprios objetos. Esse ocultamento de informações, como vere-
mos, é crucial à boa engenharia de software.
Herança
Uma nova classe de objetos pode ser criada convenientemente por meio de herança 
— ela (chamada subclasse) começa com as características de uma classe existente 
(chamada superclasse), possivelmente personalizando-as e adicionando aspectos 
próprios.
Fonte: Deitel e Deitel (2017, p. 8-10).
201
eu recomendo!
Java – Guia do Programador Atualizado para Java 8
Autor: Peter Jandl Junior
Editora: NovaTec
Sinopse: desenvolva aplicações usando o Java 8! Explore todas as 
vantagens da programação orientada a objetos por meio da ele-
gante sintaxe Java. Aprenda a usar sobrecarga, herança, classes 
abstratas, polimorfismo, interfaces, genéricos e expressões lamb-
da. Construa aplicações gráficas utilizando componentes Swing, tornando-as mul-
titarefa com as threads. Opere dados de qualquer tipo com fluxos de dados e ar-
quivos, organizando-os por meio das coleções. Manipule coleções com operações 
de filtragem, mapeamento e redução. Implemente aplicações comerciais capazes 
de acessar bancos de dados com a API JDBC ou de se comunicar em rede local e na 
Internet, por meio dos sockets e datagramas. Java – Guia do Programador abrange 
o conteúdo essencial para as certificações Oracle Certified Associate e Oracle Certified 
Professional para Java SE 5, SE 6, SE 7 e SE 8. Este livro contém quase 300 exemplos 
completos, comentados em detalhe, muitos fragmentos de código prontos para 
uso, além de diagramas, telas e dezenas de resumos da API Java. Inclui, também, 
mais de 120 exercícios de revisão. Todo o material de apoio encontra-se disponível 
no site da Novatec Editora. Principais tópicos abordados: sintaxe java orientação 
a objetos, sobrecarga e sobreposição, herança e polimorfismo, classes abstratas 
interfaces, expressões lambda, referências para métodos genéricos, componentes 
swing, coleções threads, arquivos e streams JDBC sockets e datagramas.
livro
Aula sobre interface gráfica em Java, com o professor Yuri Lacerda. É abordado, 
nesta aula: por que uma interface gráfica? Plug-ins nas IDEs, estudo de caso de 
cadastro de contato, formulário em interface gráfica, swing: JFrame, JLabel, JText-
Field, JMenu, Action Listener, programando no Eclipse. 
https://www.youtube.com/watch?v=p9mZHeWVsAg
conecte-se
202
conclusão geral
conclusão geral
202
conclusão geral
conclusão geral
Neste livro, procuramos mostrar a importância da disciplina engenharia de software 
e como ela, aliada ao desenvolvimento de software, pode ser aplicada durante o de-
senvolvimento de um sistema. A fim de possibilitar o seu entendimento, na Unidade 1, 
foram estudados os conceitos de software e a sua engenharia. 
Na Unidade 2, abordamos os recursos que garantem a integridade e o controle 
de acesso aos atributos e métodos, o encapsulamento. Por meios dos modificado-
res de acesso, verificamos que é possível dar permissão de acesso a classes que os 
utilizam, ou seja, estudamos os modificadores abstract, public, private e protected.
 Na Unidade 3, abordamos o conceito de herança: nele, estudamos, na prática, 
como aplicar a herança entre classes e tirar proveito desse recurso por meio do 
polimorfismo, que é a capacidade de especializar um método herdado do pai. Além 
da especialização, percebemos que, com a herança, reduzimos a quantidade de có-
digos, contudo aumentamos a complexidade da aplicação.
 Na Unidade 4, abordamos os recursos que funcionam como modelo de desen-
volvimento de outros de contrato: as classes abstratas e interfaces, respectivamen-
te. Na classe abstrata, temos um modelo de classes que pode ser utilizado e adap-
tado às necessidades do desenvolvedor. Já as interfaces funcionam como contrato, 
em que todos os métodos devem ser implementados.
 Para finalizar, trabalhamos, na Unidade 5, com a implementação do estudo de 
caso. Primeiramente, realizamos um estudo fazendo algumas alterações nele, o que 
possibilitou o desenvolvimento de um MVP (Minimum Viable Product, ou seja, Míni-
mo Produto Viável). 
 Esperamos ter alcançado o objetivo inicial, que era o de mostrar a importância 
da engenharia de software. Desejamos que você seja muito feliz profissionalmente, 
utilizando os conceitos apresentados aqui e, se pudermos,de alguma forma, ajudá-
-lo(a), estamos à sua disposição. 
referências
203
BOOCH, G.; RUMBAUGH, J.; JACOBSON, I. UML: Guia do Usuário. 2. ed. São Paulo: Campus, 
2006.
CLARO, D. B.; SOBRAL, J. B. M. Programação em Java. Florianópolis: Copyleft Pearson Educa-
tion, 2008.
DEITEL, H.; DEITEL, P. Java – Como Programar. 10. ed. São Paulo: Prentice Hall Brasil, 2017. 
GUEDES, G. T. A. UML 2: guia prático. São Paulo: Novatec, 2007.
GUEDES, G. T. A. UML 2: uma abordagem prática. 2. ed. São Paulo: Novatec, 2011.
LIMA, A. S. UML 2.0: do requisito à solução. São Paulo: Érica, 2009.
MELO, A. C. Desenvolvendo aplicações com UML 2.0: do conceitual à implementação. Rio de 
Janeiro: Brasport, 2004.
RICARTE, I. L. M. Departamento de Engenharia de Computação e Automação Industrial. Fa-
culdade de Engenharia Elétrica e de Computação. Programação Orientada a Objetos: Uma 
Abordagem com Java. Campinas: Unicamp, 2001. Aulas. 118p. 
SOMMERVILLE, I. Engenharia de Software. 9. ed. São Paulo: Pearson Prentice Hall, 2011.
REFERÊNCIA ON-LINE 
1 Em: https:/blog.caelum.com.br/revisitando-a-orientacao-a-objetos-encapsulamento-no-ja-
va/. Acesso em: 29 out. 2019.
gabarito
204
UNIDADE 1
1. 
2. 
3. D
4. 
Funcionario
+ Matricula : Integer
+ CpfCnpj : String
+ NomeFunc : String
+ DtAdmissao : Date
+ IncluirNovoFunc() : void
+ BuscaFunc() : void
+ ExcluirFunc() : void
Dependente
- IdDep : int
- NomeDep : String
+ DtNascimento : Date
+ IdFunc : Integer
+ IncluirNovoDep() : void
+ ExcluirDep() : void
0..*
Ônibus
- placa : char
- cor : char
- nrportas : int
- tipo_automovel : int
- quilometragem : long
- renavam : long
- valor_locacao : double
+ conAuto() : char
Modelo
- descricao : string
+ consultaMod() : void
Marca
- descricao : string
+ consultaMarca() : void
Locação
- dt_locacao : date
- hora_locacao : string
- dt_devolucao : date
- hora_devolucao : string
- quilometragem : long
- devolvido : int
+ consultaCli() : void
Cliente
- cpf_cli : long
- nome_cli : string
- end_cli : string
- tel_cli : string
- email_cli : string
+ consultaCli() : void
0..* 1..*
1..*
1..*
compõe
tem
realiza
possui
Produto
- nome : String
- unidadeCompra : int
-qntPrevistoMes : double
- precoEstimado : double
+ incluir(p1 : Produto) : void
ListaCompra
- mes : int
+ incluir(mes : int) : void
+ calcularTotal(mes : int) : void
ItemCompra
- qtdEfetivaCompra : int
+ incluir(i1 : ItemCompra) : void
0..*
1..*
gabarito
205
5. Os três modos de visibilidade são: o pú-
blico, o protegido e o privado.
• O símbolo mais (+) indica visibilidade 
pública, ou seja, significa que o atribu-
to ou o método pode ser utilizado por 
objetos de qualquer classe.
• O símbolo sustenido (#) indica que a 
visibilidade é protegida, ou seja, deter-
mina que, apenas, objetos da classe 
possuidora do atributo ou do método 
ou de suas subclasses podem acessá-lo.
• O símbolo menos (-) indica que a visi-
bilidade é privada, ou seja, somente, os 
objetos da classe possuidora do atribu-
to ou método poderão utilizá-lo.
UNIDADE 2
1. C.
2. B.
3. D.
4. Classe: casa. 
Atributos: janela, portas e quartos.
Método: inserir(), listar() e excluir().
5. Encapsulamento. 
O controle de acesso aos dados de um 
objeto envolve uma das principais ca-
racterísticas da programação orientada 
a objetos: o encapsulamento. Ele é im-
plementado pela restrição de acesso aos 
atributos. Se você não quiser que um atri-
buto seja, facilmente, modificado, pode 
torná-lo privado e permitir a sua modifi-
cação apenas por meio de um método 
público. Com esta abordagem, você pode 
validar os dados antes de atribuí-los.
UNIDADE 3
1. 
package grupo;
public class Grupo {
 public String imprimeDescricao() {
 return "Grupo";
 }
 public static void main(String[] args) {
 System.out.println(new Grupo().
imprimeDescricao());
 System.out.println(new SubGrupo().
imprimeDescricao());
 System.out.println(new Produto().
imprimeDescricao());
 } 
}
------------------------------
package grupo;
public class SubGrupo extends Grupo {
 @Override
 public String imprimeDescricao() {
 return "Sub-Grupo";
 }
}
------------------------------
package grupo;
public class Produto extends SubGrupo {
 @Override
 public String imprimeDescricao() {
 return "Produto";
 }
}
2. 
package Principal;
public class Materiais {
 protected String assunto;
 protected String titulo;
gabarito
206
 public String getAssunto() {
 return assunto;
 }
 public void setAssunto(String 
assunto) {
 this.assunto = assunto;
 }
 public String getTitulo() {
 return titulo;
 }
 public void setTitulo(String titulo) {
 this.titulo = titulo;
 }
 public void mostrarGeral(){
 System.out.println("Assunto:"+ 
this.getAssunto());
 System.out.println("Título: 
"+this.getTitulo());
 } 
}
------------------------------
package Principal;
public class Livros extends Materiais{
 private String editora, isbn, autor;
 private int edicao;
 public String getEditora() {
 return editora;
 }
 public void setEditora(String 
editora) {
 this.editora = editora;
 }
 public String getIsbn() {
 return isbn;
 }
 public void setIsbn(String isbn) {
 this.isbn = isbn;
 }
 public String getAutor() {
 return autor;
 }
 public void setAutor(String autor) {
 this.autor = autor;
 }
 public int getEdicao() {
 return edicao;
 }
 public void setEdicao(int edicao) {
 this.edicao = edicao;
 }
 
 @Override
 public void mostrarGeral(){
 super.mostrarGeral();
 System.out.println("Au-
tor:"+this.getAutor());
 System.out.println("ISBN:"+this.
getIsbn());
 System.out.println("Edição:"+-
this.getEdicao());
 System.out.println("Editora:"+-
this.getEditora());
 }
}
------------------------------
package Principal;
public class Revista extends Materiais{
 private String colecao, editora;
gabarito
207
 public String getColecao() {
 return colecao;
 }
 public void setColecao(String 
colecao) {
 this.colecao = colecao;
 }
 public String getEditora() {
 return editora;
 }
 public void setEditora(String 
editora) {
 this.editora = editora;
 }
 
 @Override
 public void mostrarGeral(){
super.mostrarGeral();
 System.out.println("Coleção:"+-
this.getColecao());
 System.out.println("Editora:"+-
this.getEditora());
 }
}
3. 
package Principal;
public class Principal {
 public static void main(String[] args) {
 Livros l1 = new Livros();
 System.out.println("-- Dados do 
Livro --");
 l1.setAssunto("Modelagem UME e 
Programação Orientada a Objetos em 
Java");
 l1.setAutor("Rafael Alves Flo-
rindo");
 l1.setEdicao(1);
 l1.setEditora("Unicesumar");
 l1.setIsbn("2831283912047");
 l1.setTitulo("Programação III");
 l1.mostrarGeral();
 System.out.println("-- Dados da 
Revista --");
 Revista r1 = new Revista();
 r1.setAssunto("Modelagem UME e 
Programação Orientada a Objetos em 
Java");
 r1.setTitulo("Programação III");
 r1.setColecao("Programação");
 r1.setEditora("Unicesumar");
 r1.mostrarGeral();
 }
}
4. 
public class Ouvidoria {
 private String nome, email, assunto;
 public String getAssunto() {
 return assunto;
 }
 public void setAssunto(String assunto) {
 this.assunto = assunto;
 }
 public String getNome() {
 return nome;
 }
 public void setNome(String nome) {
 this.nome = nome;
 }
 public String getEmail() {
gabarito
208
 return email;
 }
 public void setEmail(String email) {
 this.email = email;
 }
 @Override
 public String toString() {
 return "Ouvidoria{" + "nome=" + 
nome + ", email=" + email + ", as-
sunto=" + assunto + '}';
 }
 public Ouvidoria(String nome, 
String email, String assunto) {
 this.nome = nome;
 this.email = email;
 this.assunto = assunto;
 
------------------------------
import java.util.Scanner;
public class Principal {
 public static void main(String[] 
args) {
 String nome, email, assunto;
 Scanner tec = new Scanner(System.
in);
 System.out.println("Informe o 
seu nome: ");
 nome = tec.nextLine();
 System.out.println("Informeo seu 
email: ");
 email = tec.nextLine();
 System.out.println("Informe o 
seu Assunto: ");
 assunto = tec.nextLine();
 Ouvidoria ouvidoria = new Ouvido-
ria(nome, email, assunto); 
 
 System.out.println(ouvidoria.
toString());
 }
}
5. 
import java.util.Scanner;
public class Pagamento {
 private double valor;
 private String titulo, propretario;
 public double getValor() {
 return valor;
 }
 public void setValor(double valor) {
 this.valor = valor;
 }
 public String getTitulo() {
 return titulo;
 }
 public void setTitulo(String ti-
tulo) {
 this.titulo = titulo;
 }
 public String getPropretario() {
 return propretario;
 }
 public void setPropretario(S-
tring propretario) {
 this.propretario = propretario;
 }
 public void inserir(){
 Scanner tec = new Scanner(System.
in);
 System.out.println("Digite o 
Proprietario");
 this.setPropretario(tec.nextLi-
ne());
 System.out.println("Digite o Ti-
tulo");
gabarito
209
 this.setTitulo(tec.nextLine());
 System.out.println("Digite o va-
lor");
 this.setValor(Double.parseDoub-
le(tec.nextLine()));
 }
 public void imprimir(){
 System.out.println("Titulo: 
"+getTitulo());
 System.out.println("Proprietá-
rio: "+getPropretario());
 System.out.println("Valor: "+ge-
tValor());
 S y s t e m . o u t . p r i n t
ln("----------------------");
 }
}
------------------------
public class Principal {
 static Pagamento p[] = new Paga-
mento[4];
 public static int ultimo = 0;
 public static void imprimeP(){
 for(int i = 0; i < ultimo; i++){
 p[i].imprimir();
 System.out.println ("---------
-------------");
 }
 }
 public static void main(String[] 
args) {
 int i; 
 for (i = 0; i < 4; i++){
 p[i] = new Pagamento();
 p[i].inserir();
 ultimo++;
 }
 imprimeP();
 }
}
UNIDADE 4
1. A
2. B
3. C
4. 
Classe Pessoa
package livroabstrato;
abstract public class Pessoa {
 private String nome, dataNascimento;
 public Pessoa() {
 }
 public String getNome() {
 return nome;
 }
 public void setNome(String nome) {
 this.nome = nome;
 }
 public String getDataNascimento() {
 return dataNascimento;
 }
 public void setDataNascimento(S-
tring dataNascimento) {
 this.dataNascimento = dataNasci-
mento;
 }
 
 public abstract void cadastro();
}
Classe Colaborador
package livroabstrato;
public class Colaborador extends 
Pessoa {
 @Override
 public void cadastro() {
 this.setNome("Rafael");
 this.setDataNascimento("02/12/1982");
gabarito
210
 }
 public void listar(){
 System.out.println("Nome: " + 
this.getNome());
 System.out.println("Data de Nas-
cimento: " + this.getDataNascimen-
to());
 } 
}
classe Principal
package livroabstrato;
public class Principal {
 public static void main(String[] 
args) {
 Colaborador colab1 = new Colabo-
rador();
 colab1.cadastro();
 colab1.listar();
 } 
}
5. 
Interface Controle
package interfacecontrolelivro;
public interface Controle {
 public void cadastrar();
 public void listar();
}
Classe Livro
package interfacecontrolelivro;
public class Livro implements Controle {
 private String autor;
 public String getAutor() {
 return autor;
 }
 public void setAutor(String autor){
 this.autor = autor;
 }
 
 @Override
 public void cadastrar() {
 this.setAutor("Rafael Alves Flo-
rindo");
 }
 @Override
 public void listar() {
 System.out.println("Autor: " + 
this.getAutor());
 } 
}
Classe Principal
package interfacecontrolelivro;
public class Principal {
 public static void main(String[] 
args) {
 Livro livro = new Livro();
 livro.cadastrar();
 livro.listar();
 } 
}
UNIDADE 5
1. 
package banco;
public class ContaCorrente {
 private String agencia;
 private String conta;
 private String cpf;
 private double saldo=0;
 public String getAgencia() {
gabarito
211
 return agencia;
 }
 public void setAgencia(String 
agencia) {
 this.agencia = agencia;
 }
 public String getConta() {
 return conta;
 }
 public void setConta(String 
conta) {
 this.conta = conta;
 }
 public String getCpf() {
 return cpf;
 }
 public void setCpf(String cpf) {
 this.cpf = cpf;
 }
 public double getSaldo() {
 return saldo;
 }
 public void setSaldo(double 
saldo) {
 this.saldo = saldo;
 }
 public void depositar(double 
valor){
 this.setSaldo(this.getSal-
do() + valor);
 System.out.println(valor + " 
Valor Depositado com sucesso");
 }
 public void sacar(double valor){
 if (this.getSaldo() < valor){
 System.out.println("Impos-
sível Sacar, saldo insuficiente");
 }else{
 this.setSaldo(this.getSal-
do() - valor);
 System.out.println(valor + " 
Valor resgatado com sucesso");
 } 
 }
 public void imprimirSaldo(){
 System.out.print ln("------
---------------------------");
 System.out.println("Agen-
cia: " + this.getAgencia());
 System.out.println("Conta: 
" + this.getConta());
 System.out.println("CPF: " + 
this.getCpf());
 System.out.println("Saldo: 
" + this.getSaldo());
 System.out.print ln("------
---------------------------");
 }
}
package banco;
public class Movimento {
 public static void main(String[] 
args) {
 ContaCorrente conta1 = new 
ContaCorrente();
 conta1.setAgencia("Centro");
 conta1.setConta("12345");
 conta1.setCpf("123456789");
 conta1.imprimirSaldo();
 
 conta1.depositar(500.00);
 conta1.imprimirSaldo();
 
 conta1.sacar(200.00);
 conta1.imprimirSaldo();
 
 conta1.sacar(400.00);
 conta1.imprimirSaldo();
 }
}
gabarito
212
2) D.
3) C.
4) B.
5) Sim, ocorre um problema. O método 
main está tentando atribuir um va-
lor de telefone à variável telefone, 
que é local (pertencente ao méto-
do “telefonar”, portanto, só pode 
ser visualizada e acessada de dentro 
dele). Para solucionar o problema, 
uma das alternativas é tornar a va-
riável “telefonar” uma variável de 
instância, deixando-a no escopo da 
classe. A seguir, é demonstrado o 
resultado da correção.
public static void main(String[] args) {
 Pessoa pessoa = new Pessoa ();
 pessoa.telefone = "3377-5654";
 pessoa.telefonar ();
}
public class Pessoa {
 public String nome;
 public int idade;
 public String telefone = "3322-5599";
 public void telefonar() {
 System.out.println ("Ligar para" + 
telefone);
 }
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
anotações
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
anotações
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
anotações
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
anotações
	MODELAGEM DE
	SISTEMAS
	MODIFICADORES
	JAVA e
	ENCAPSULAMENTO
	HERANÇA E 
	POLIMORFISMO
	CLASSES
	ABSTRATAS
	e Interfaces
	ESTUDO DE CASO: 
	ANÁLISE CLÍNICA
	conclusão geral
	h.j3faof3fxm9o
	_GoBack

Mais conteúdos dessa disciplina

Mais conteúdos dessa disciplina