Logo Passei Direto
Buscar
Material
páginas com resultados encontrados.
páginas com resultados encontrados.

Prévia do material em texto

W
BA
13
62
_V
1.
0
PROGRAMAÇÃO 
ORIENTADA A OBJETOS
2
Anderson da Silva Marcolino
São Paulo
Platos Soluções Educacionais S.A 
2023
PROGRAMAÇÃO ORIENTADA A OBJETOS
1ª edição
3
2023
Platos Soluções Educacionais S.A
Alameda Santos, n° 960 – Cerqueira César
CEP: 01418-002— São Paulo — SP
Homepage: https://www.platosedu.com.br/
Head de Platos Soluções Educacionais S.A
Silvia Rodrigues Cima Bizatto
Conselho Acadêmico
Alessandra Cristina Fahl 
Ana Carolina Gulelmo Staut
Camila Braga de Oliveira Higa
Camila Turchetti Bacan Gabiatti
Giani Vendramel de Oliveira
Gislaine Denisale Ferreira
Henrique Salustiano Silva
Mariana Gerardi Mello
Nirse Ruscheinsky Breternitz
Priscila Pereira Silva
Coordenador
Henrique Salustiano Silva
Revisor
Fabiano Gonçalves dos Santos
Editorial
Beatriz Meloni Montefusco
Carolina Yaly
Márcia Regina Silva
Paola Andressa Machado Leal
Dados Internacionais de Catalogação na Publicação (CIP)_____________________________________________________________________________ 
 Marcolino, Anderson da Silva
Programação orientada a objetos/ Anderson da Silva 
 Marcolino. – São Paulo: Platos Soluções Educacionais S.A. 
2023 
 32 p.
ISBN 978-65-5356-441-1
 1. Programação. 2. Software. 3. Orientada a objetos. I. 
Título. 3. Técnicas de speaking, listening e writing. I. Título. 
CDU 004.3
_____________________________________________________________________________ 
Raquel Torres – CRB 8/10534
M321p 
© 2023 por Platos Soluções Educacionais S.A.
Todos os direitos reservados. Nenhuma parte desta publicação poderá ser reproduzida ou 
transmitida de qualquer modo ou por qualquer outro meio, eletrônico ou mecânico, incluindo 
fotocópia, gravação ou qualquer outro tipo de sistema de armazenamento e transmissão de 
informação, sem prévia autorização, por escrito, da Platos Soluções Educacionais S.A.
https://www.platosedu.com.br/
4
SUMÁRIO
Apresentação da disciplina __________________________________ 05
Histórico e pilares da programação orientada a objetos _____ 07
Abstração e herança em orientação a objetos _______________ 19
Encapsulamento e instanciação de objetos __________________ 39
Implementação de interfaces gráficas com Java ______________ 56
PROGRAMAÇÃO ORIENTADA A OBJETOS
5
Apresentação da disciplina
No contexto de desenvolvimento de software, temos diversas 
tecnologias para desenvolver soluções para diversos problemas. Dentre 
tais tecnologias, destacamos linguagens de programação orientada 
a objetos. É neste contexto que, nesta disciplina, entenderemos o 
surgimento do paradigma orientado a objetos, seus fundamentos e 
como podemos utilizar todo o seu poder de reuso para desenvolver 
softwares utilizando a linguagem de programação Java.
A disciplina está dividida em quatro módulos. No primeiro, veremos 
como a orientação a objetos surgiu a partir de um breve histórico. 
Conceituaremos os pilares fundamentais da orientação a objetos e 
como estes se integram, permitindo usufruir de diversos benefícios, os 
quais serão discutidos e apresentados também. Neste mesmo módulo, 
veremos conceitos sobre a linguagem de modelagem unificada, que 
permite representarmos graficamente representações dos elementos 
contidos em um programa orientado a objetos.
No segundo módulo, veremos a utilização dos pilares para programar 
em Java. Utilizaremos o pilar de abstração para entender como 
criamos os objetos em Java, seus estados e seus comportamentos. 
Adicionalmente, utilizaremos o pilar de herança, ainda que em menor 
profundidade.
No terceiro módulo, utilizaremos os pilares de encapsulamento e 
nos aprofundaremos nos conceitos de herança. Entenderemos como 
instanciar objetos de classes e os segredos por trás dos métodos 
construtores, bem como o que são a generalização e a especialização.
6
No quarto e último módulo, utilizaremos um pacote Java específico para 
criação de interfaces gráficas de usuário, por meio do desenvolvimento 
de uma aplicação que nos permitirá colocar em prática tudo que foi 
aprendido nos módulos anteriores e avançar ainda mais na linguagem.
Assim, conseguiremos formar uma base sólida para que possamos nos 
aventurar ainda mais em Java e na sua vasta gama de bibliotecas, ou 
migrarmos para outras linguagens de programação orientada a objetos.
Desejo bons estudos!
7
Histórico e pilares da 
programação orientada a objetos
Autoria: Anderson da Silva Marcolino
Leitura crítica: Fabiano Gonçalves dos Santos
Objetivos
• Compreender o histórico e a evolução dos 
paradigmas de programação até o paradigma de 
orientação a objetos.
• Estabelecer os pilares que fundamentam a 
programação orientada a objetos.
• Compreender via código e representações da 
Linguagem de Modelagem Unificada (UML) os 
conceitos fundamentais do paradigma orientado a 
objetos.
8
1. Introdução e histórico do paradigma de 
programação orientada a objetos
A linguagem de programação orientada a objetos (OO) tem seu foco 
dirigido à representação de objetos reais, suas características e seus 
comportamentos. Essa representação, além de permitir uma melhor 
abstração de objetos, garante o reuso.
Neste contexto, a criação e o desenvolvimento, bem como a evolução 
das linguagens de programação OO, são alicerçados em benefícios, com 
destaque para o reuso. Deste modo, torna-se importante conhecer 
o motivo de tal concepção e como ela atingiu o estágio em que se 
encontra hoje, por meio de um breve histórico.
Inicialmente, o conceito de orientação a objetos estava voltado 
à representação de objetos reais por meio de um paradigma de 
programação. Um paradigma pode ser definido com um conjunto de 
elementos, no caso de uma linguagem de programação, que criam 
um modelo, mas, antes de OO, temos outros paradigmas adotados 
(MICHAELIS, 1998).
Os primeiros paradigmas de programação foram os funcionais e 
imperativos, utilizados na área de Exatas no contexto da Máquina de 
Turing e do cálculo Lambda, por volta de 1030. Enquanto a Máquina 
de Turing utilizava cartões perfurados para processamento de baixo 
para cima (bottom-up), passo a passo, o cálculo Lambda representa 
um processamento que vai de cima para baixo (top-down), em uma 
abordagem voltada à utilização de funções.
Deste modo, em muitos livros, temos a adoção do termo top-down 
para as linguagens de programação procedurais. Nos anos seguintes, 
por volta de 1940, linguagens de programação de baixo nível, como 
9
Assembly, foram criadas. Na sequência, nos anos de 1950, linguagens de 
alto nível, como COBOL e FORTRAN, ambas imperativas, foram criadas.
Somente na década de 1960 que o termo programação orientada a 
objetos foi cunhado por Alan Kay, em seu trabalho de graduação. No 
entanto, foi em 1965 que foi criada a primeira linguagem reconhecida, 
de fato, como uma linguagem orientada a objetos: a Simula. Essa 
linguagem introduziu conceitos, como classes, herança, subclasses e 
métodos virtuais (aqueles que serão sobrescritos nas subclasses).
O mesmo idealizador do conceito de OO criou, junto a outros 
pesquisadores, a linguagem Smalltalk, contudo esta era mais funcional 
do que orientada a objetos. Somente quando intitulada de Smalltalk-72 
que se tornou uma linguagem mais orientada a objetos que a Simula. 
Alan classifica as características essenciais para que uma linguagem 
de programação seja assim designada, sendo elas a passagem de 
mensagens, o encapsulamento e a vinculação dinâmica.
Em 1991, a Sun Microsystems criou a linguagem que seria uma das mais 
famosas no contexto de programação orientada a objetos, a linguagem 
Java, a qual, hoje, se encontra na sua versão 18 (JECK, 2021).
Considerando as características preconizadas por Alan e as integradas 
em Java, podemos destacar o que torna o paradigma de OO tão 
importante (ELLIOTT, 2020):
• Representação de objetos do mundo real por meio de 
suas características ou propriedades e de suas ações ou 
comportamentos.
• Capacidade de troca de mensagens e alteração de estados por 
meio de meiosespecíficos, sem que os estados mutáveis estejam 
disponíveis a todo o código.
10
• Estabelecimentos claros dos objetos, seus papéis e, 
consequentemente, a dissociação entre eles, tornando-os únicos.
• Capacidade de adaptabilidade e resiliência a mudanças, em 
especial, no tempo de execução, ou seja, quando o programa já 
está sendo executado.
Porém, para que tais conceitos e benefícios possam ser adotados, 
precisamos entender de fato os conceitos iniciais que integram o 
paradigm de OO. É o que estudaremos a seguir.
2. Conceitos essenciais de OO
Considerando o próprio nome do paradigma – orientação a objetos –, 
temos um elemento essencial e central: o objeto.
Um objeto é uma entidade do mundo real, seja esta entidade concreta 
(uma pessoa) ou abstrata (um personagem de uma história), que pode 
ser descrita por meio de características e estados e que pode realizar 
ações ou possuir determinados comportamentos (PRESSMAN; MAXIM, 
2021). Deste modo, um objeto em OO é representado por meio de 
atributos, que refletem o estado e as propriedades, e por métodos, que 
refletem as ações ou os comportamentos que pode realizar.
Por exemplo, um objeto do tipo pessoa poderia possuir os seguintes 
atributos e valores:
• Nome: João.
• Idade: 42 anos.
• Altura: 180 cm.
• Peso: 80 kg.
11
• Raça: Parda.
E os seguintes comportamentos:
• Mover().
• Subir().
• Pular().
• Comer().
Contudo, para que tais objetos sejam criados, temos um elemento a ser 
criado previamente. Ele permite que possamos criar mais de um objeto 
do mesmo tipo, ou seja, poderíamos criar mais de uma Pessoa, e esta 
possuir valores de seus atributos diferentes dos do objeto “João”. Este 
elemento são as classes.
Enquanto o objeto é uma instância, ou seja, a definição de um objeto 
por meio da especificação de seus atributos e métodos, e como esses 
interagem ou realizam as ações do objeto Pessoa instanciado, a classe 
serve de molde, e designa quais atributos uma pessoa terá, bem como 
seus métodos.
A representação de objetos do mundo real, por meio de objetos 
instanciados e sua instanciação, considerando as classes, é um dos 
quatro pilares da OO, sendo conhecido como abstração.
Assim, a abstração é a capacidade de conseguirmos expressar via 
propriedades e comportamentos, ou seja, atributos e métodos, objetos 
do mundo real. Como já mencionados, tais objetos podem ser abstratos 
ou concretos, como uma conta a pagar, um personagem de jogo, uma 
pessoa, um prédio etc. (JECK, 2021).
Considerando tal pilar, temos o segundo pilar, que é originário pela 
possibilidade de especificarmos os “moldes” que permitirão a instância 
12
de um ou mais objetos: a herança. É importante frisar que o termo 
instância é padronizado e serve para indicar que estamos criando um 
objeto a partir de uma classe.
A herança ocorre na relação de uma classe com outra, ou entre múltiplas 
classes de modo encadeado. Em linguagens como Java, não podemos 
ter uma classe que herde características e métodos de mais de uma 
classe, ou seja, não há heranças múltiplas, devido às dificuldades de se 
determinar à qual classe um método pertence. Este problema é tratado 
em tópicos mais avançados sobre OO. O importante, neste momento, é 
nos atentarmos ao conceito de herança.
A herança permite, então, que uma classe estenda os atributos e 
métodos de uma classe à outra, permitindo a criação de objetos 
especialistas. Dizemos que a classe pai é uma superclasse, enquanto 
a classe filha é uma subclasse. Dentre elas, temos os conceitos de 
generalização e especialização. É algo similar quando temos uma família 
que passa, por herança, os seus bens aos filhos, e os filhos, por si só, 
utilizam-se de tais bens como lhes convir.
Na generalização, a classe pai é mais genérica, ou por analogia, podemos 
dizer que a classe pai não possui tantos atributos ou métodos quanto a 
classe filha, a qual, por ser mais “nova”, se torna especialista em algo e 
pode, portanto, aprender mais coisas que o pai. A Figura 1 apresenta a 
relação de herança entre duas classes filhas por meio de um diagrama 
de classes da Linguagem de Modelagem Unificada (UML) (PRESSMAN; 
MAXIM, 2021).
13
Figura 1 – Classe Pessoa e Subclasses Funcionário e Gerente
Fonte: elaborada pelo autor.
A superclasse, ou classe pai, na Figura 1, é representada pela classe 
“Pessoa”. Por padronização, sempre um nome de classe deverá ser 
iniciado por letra maiúscula, já atributos e métodos iniciam com letra 
minúscula. Além disso, os métodos são, geralmente, verbos no infinitivo. 
Quando um método possuir um nome composto, como é o caso do 
método “realizarTreinamento()”, a segunda, ou as demais palavras 
unidas, deverá iniciar com letra maiúscula (GUERRA, 2014).
As padronizações auxiliam na leitura e na identificação dos elementos, 
tanto nos diagramas quanto no código, e devem ser adotadas 
independentemente da linguagem de programação adotada.
Na superclasse, temos cinco atributos e quatro métodos. Os atributos 
ficam representados na parte seguinte ao título da classe, seguidos 
pelos métodos. Em alguns diagramas, com menos especificidade, temos 
o ocultamento dos métodos e atributos, mas a visão mais comum é a 
apresentada na Figura 1.
14
Seguidas da superclasse, temos duas classes filhas, a classe 
“Funcionario” e a classe “Gerente”. Note que, por padronização, não 
se utiliza acentuação no nome de classes, métodos ou atributos. Tais 
subclasses estão herdando as características da classe pai “Pessoa” 
e adicionam, considerando suas especificidades, um atributo e um 
método a mais para cada.
No caso da subclasse “Funcionario”, ela é uma classe especialista 
da classe “Pessoa”, que, por sua vez, é uma generalização para a 
classe “Pessoa”. Logo, a classe filha “Funcionario” possui um atributo 
especifico dela, que é “especializacao” e um método específico, o 
“realizarTreinamento()”. Este estado e comportamento não são 
reconhecidos pela classe pai, por isso diz-se que a classe filha é 
especialista. Por analogia, o filho estudou mais que o pai e, portanto, 
sabe mais que ele.
No contexto de herança, é importante destacar que a linguagem de 
modelagem unificada (UML), por meio de sua notação, destaca o 
relacionamento de herança existente, devido aos relacionamentos por 
meio de setas com pontas vazadas que relacionam “Funcionario” e 
“Gerente” à superclasse “Pessoa”.
A UML foi criada justamente para auxiliar na representação dos 
diferentes elementos e características que um software orientado 
a objetos pode possuir, auxiliando na criação do projeto e dos 
diagramas que servirão para o desenvolvimento posterior, garantindo 
melhor qualidade e padronização do produto em diferentes fases de 
desenvolvimento (WAZLAWICK, 2019).
Ao considerar a OO e a representação no diagrama de Figura 1, temos 
a possibilidade de instanciar objetos da classe “Funcionario” e “Gerente” 
apenas. Isso ocorre porque, também por padronização da UML, a classe 
pai é, geralmente, especificada como sendo uma classe abstrata, ou seja, 
ela não permite instanciar um objeto dela.
15
O conceito de classe abstrata designa um contrato de herança, em que 
a classe pai pode não ter código no interior dos seus métodos, sendo 
estes implementados especificamente nas classes filhas, ou seja, as 
classes que herdam os atributos e métodos da classe pai.
Temos, deste modo, o que chamamos de classes concretas, que 
permitem instanciar objetos – sendo este o caso das classes filhas –, 
e a classe abstrata, que é representada pela classe pai, no contexto 
apresentado, que não permite a instanciação de um objeto. A classe 
abstrata atua como um contrato que obriga as classes filhas a 
implementarem seus métodos.
Na perspectiva de métodos abstratos das classes abstratas, temos 
um terceiro pilar de OO, o que chamamos de polimorfismo, ou seja, 
várias formas. O polimorfismo condiz com a capacidade das classes 
filhas de implementarem de modo diferente o método da classe pai. 
Se um método da classe pai possuir um comportamentoou não o 
implementar, quando o método for abstrato, a classe filha, que herdou 
seus métodos, terá de implementá-los, reescrevendo-os, o que dá nome 
ao conceito de polimorfismo.
No total, há dois tipos de polimorfismo: o de sobrescrita e o de 
sobrecarga. O de sobrescrita reescreve o código do corpo do método 
e, assim, realiza um comportamento totalmente diferente da classe 
da qual herdou tal método. Já no contexto da sobrecarga, a relação 
de polimorfismo não ocorre entre classes pais e filhas, mas, sim, no 
corpo da classe filha, no qual a assinatura do método, por exemplo, 
“gerenciarDepartamento()”, é reutilizado quantas vezes forem 
necessárias, porém com uma quantidade e tipos de parâmetros 
específicos para cada reutilização.
Deste modo, a sobrecarga ocorre na passagem de parâmetros. 
O método “gerenciarDepartamento(int i)” e o método 
“gerenciarDepartamento(int i, String x)” são sobrecarregados, visto que 
16
um recebe apenas um parâmetro do tipo inteiro (o que está sendo 
passado dentro dos parâmetros da assinatura do método) e o outro 
recebe dois parâmetros. No caso da linguagem Java, por exemplo, o 
código saberá qual método chamar, de acordo com a quantidade e 
os tipos de parâmetros passados para o método. Essa característica 
permite a reutilização de métodos e redução de escopo no contexto dos 
métodos, propiciando reuso (JECK, 2021).
Ainda considerando a Figura 1, temos o último dos pilares da OO, o 
encapsulamento. O encapsulamento permite que os estados (atributos) 
dos objetos não sejam alterados sem utilizar os próprios métodos do 
objeto que se deseja modificar. Isso garante a integridade de autonomia 
dos objetos, trazendo garantia de que os valores não serão alterados 
por qualquer objeto ou método que estiver no código.
O encapsulamento está representado no digrama de classes da Figura 
1 por meio dos sinais de “+” e “-” na frente dos atributos e métodos. No 
caso, os atributos são privados (do termo em inglês private) ou públicos 
(do termo em inglês public), quanto aos métodos. Deste modo, não 
será possível fazer uma atribuição de valores para os atributos sem a 
chamada de um método, bem como obter o valor atual mantido em um 
estado do objetos. Para isso, são utilizados os métodos padronizados 
e intitulados getters e setters, que, em português, seriam traduzidos 
para “buscadores” e “alteradores”, mas são chamados nos contextos de 
desenvolvimento com o termo em inglês.
Os métodos getters e setters não são, geralmente, apresentados nos 
diagramas da UML, pois estes são obrigatórios, tão logo que um atributo 
é declarado ou representado como private. Por exemplo, para a classe 
“Funcionario”, seriam necessários seis métodos get e seis métodos set, 
para que seja possível obter os valores dos seis atributos e alterar o 
valor dos seis atributos, respectivamente.
Por exemplo, para o atributo “nome”, o objeto instanciado, seja ele 
da classe “Funcionario” ou “Gerente”, terá de implementar o método 
17
“getNome(): String” e o método “setNome(String nome)”. No primeiro, 
há um retorno de valor do tipo String, ou seja, cadeia de caracteres, 
enquanto, no segundo, há uma passagem de um parâmetro, também 
do tipo cadeia de caracteres, para que o atribuo “nome” possa ser 
retornado ou alterado, respectivamente. Esta declaração deve se repetir 
para os demais atributos existentes, os quais, por padrão, devem ser 
declarados como privados. O Quadro 1 resume os tipos de visibilidade 
no contexto do modificador de acesso e encapsulamento.
Quadro 1 – Resumo dos modificadores de acesso em Java
Visibilidade public 
(público)
protected 
(protegido)
default 
(padrão)
private 
(privado)
Na mesma classe. Visível Visível Visível Visível
Nível de qualquer classe no 
mesmo pacote. Visível Visível Visível Restrito
Nível de classe filha 
no mesmo pacote. Visível Visível Visível Restrito
Nível de classe filha 
em pacotes diferentes. Visível Visível Restrito Restrito
Nível de qualquer classe 
em pacotes diferentes. Visível Restrito Restrito Restrito
Fonte: elaborado pelo autor.
Os tipos de modificadores de visibilidades apresentados no Quadro 
1 compõem e ampliam o encapsulamento de código no contexto 
de Java e outras linguagens orientadas a objetos. Há modificadores 
específicos que limitam a visibilidade de código entre as classes e, 
consequentemente, entre os objetos delas instanciados.
O modificador public dá permissão de acesso geral em qualquer tipo de 
visibilidade. O protected restringe a visibilidade entre classes em pacotes 
diferentes. O modificador default, isto é, quando não há indicação de 
modificador, restringe o acesso entre classes, sejam estas filhas ou pais, 
no contexto de pacotes diferentes. Já o mais restrito, o private, permite a 
visibilidade do que for marcado como privado ao nível da mesma classe.
18
Finalmente, os modificadores de visibilidade podem ser aplicados para 
classes, atributos e métodos. Deste modo, conseguimos identificar e 
observar os quatro principais pilares que definem a OO: abstração, 
herança, polimorfismo e encapsulamento. Todos os pilares estão 
relacionados diretamente com as classes, os atributos e os métodos e, 
consequentemente, os objetos que serão instanciados destas classes 
(PRESSMAN; MAXIM, 2021; WAZLAWICK, 2019).
Notam-se, ainda, padrões para a nomenclatura de cada elemento, 
apresentados, em especial, na Figura 1, que, seguindo a Linguagem 
de Modelagem Unificada (UML) utilizada para a representação de 
projetos com linguagens orientadas a objetos, utiliza notação própria 
e padronizada para facilitar a conversação entre as partes durante a 
concepção de um projeto de software.
Os conceitos dos quatro pilares podem ser identificados e aplicados em 
diferentes tipos de linguagens orientadas a objetos, deste modo, carece 
de estudo aprofundado para seu entendimento e aplicação, em especial, 
nos documentos que especificam a linguagem a ser utilizada. Desejo 
bons estudos!
Referências
ELLIOTT, E. Composing software: an exploration of functional programming and 
object composition in JavaScript. [S. l.]: Lean Publishing, 2020.
GUERRA, E. Design Patterns com Java: projeto orientado a objetos guiado por 
padrões. São Paulo, SP: Casa do Código, 2014.
JECK, D. Introduction to programming using Java. Geneva, NY: Hobart and William 
Smith Colleges, 2021.
MICHAELIS. Moderno dicionário da língua portuguesa. São Paulo, SP: 
Melhoramentos, 1998.
PRESSMAN, R. S.; MAXIM, B. R. Engenharia de software. São Paulo, SP: McGraw Hill 
Brasil, 2021.
WAZLAWICK, R. Engenharia de software: conceitos e práticas. São Paulo, SP: 
Elsevier, 2019.
19
Abstração e herança em 
orientação a objetos
Autoria: Anderson da Silva Marcolino
Leitura crítica: Fabiano Gonçalves dos Santos
Objetivos
• Compreender de modo mais avançado o conceito de 
abstração na orientação a objetos.
• Estabelecer como o conceito de abstração é aplicado 
na herança.
• Compreender, via código e representações de 
herança, o funcionamento da herança, considerando 
a linguagem Java.
20
1. Abstraindo o mundo real
A orientação a objetos (OO) transforma objetos abstratos ou concretos 
em representações que possam ser controladas nas mais diferentes 
aplicações, desenvolvidas com uma linguagem de programação que seja, 
consequentemente, orientada a objetos.
O ato de abstrair algo é a ação ou o efeito de isolar algo de um todo para 
considerá-lo individualmente (MICHAELIS, 1998). A abstração em OO nos 
permite representar um objeto, ocultando seus dados ou propriedades 
internas, bem como sua implementação do mundo externo, sendo, 
portanto, capaz de representar um objeto do mundo real para uma 
aplicação a ser utilizada por usuários (JECK, 2021).
Podemos comparar o exemplo de um robô aspirador de pó. Ele possui 
um controle via aplicativo, no qual você pode configurar e gerenciar 
o seu funcionamento. Para isso, você não precisa saber que peças 
estão internamente no robô. A complexidade lógica e suas peças estão 
completamente ocultas paranós, usuários finais. É deste modo que um 
objeto é representado em OO para quem o utiliza, mas, internamente, o 
desenvolvedor se preocupa em representar todos os elementos lógicos 
necessários para o funcionamento do equipamento.
Considerando o mesmo exemplo do robô aspirador, teremos diversas 
especificidades, porém, em uma linguagem orientada a objetos, 
buscamos representar um modelo genérico, o qual, com a atribuição de 
valores específicos às propriedades e com comportamentos também 
específicos, conseguirá “atuar” de modo diferente dos outros. É aí que 
temos as classes. A Figura 1 representa um esquema de abstração do 
nosso exemplo do aspirador de pó robô.
21
Figura 1 – Abstração do objeto aspirador de pó robô
Fonte: adaptada de https://www.flaticon.com/free-icons/robot-vacuum-cleaner. 
Acesso em: 2 maio 2023.
Na Figura 1, podemos observar o processo de abstração de um objeto 
real, no caso, o aspirador de pó robô, a lista de suas propriedades e 
ações e, ao final, sua representação em uma classe. Note que, para 
criarmos a lista de propriedades e ações, podemos fazer diversos 
questionamentos sobre o objeto a ser abstraído, por exemplo: qual é a 
cor do objeto? Qual é o modelo? O objeto para ao se deparar com um 
obstáculo? De um modo mais genérico, podemos questionar quais são 
as propriedades, características ou atributos do objeto? Quais são as 
ações, as funcionalidades ou os comportamentos do objeto? E assim por 
diante.
Note, ainda, que as perguntas são genéricas e não se referem a um 
modelo específico, o que indica que estamos abstraindo em nível de 
classe. O modelo será especificado somente quando instanciarmos 
um objeto. Vejamos como fica esta representação via código Java. 
Consideraremos também os getters e setters, ou seja, os métodos 
que tratam do encapsulamento dos atributos, visto que todos estão 
encapsulados para manter a privacidades dos atributos existentes.
22
1. public class Aspirador {
2. private String cor;
3. private String modelo;
4. private String tipoControle;
5. private String tipoAplicativo;
6. private String tipoLimpeza;
7. private String voltagem;
8. public String getCor() {
9. return cor;
10. }
11. public void setCor(String cor) {
12. this.cor = cor;
13. }
14. public String getModelo() {
15. return modelo;
16. }
17. public void setModelo(String modelo) {
18. this.modelo = modelo;
19. }
20. public String getTipoControle() {
21. return tipoControle;
22. }
23. public void setTipoControle(String tipoControle) {
24. this.tipoControle = tipoControle;
25. }
26. public String getTipoAplicativo() {
27. return tipoAplicativo;
28. }
29. public void setTipoAplicativo(String tipoAplicativo) {
30. this.tipoAplicativo = tipoAplicativo;
31. }
32. public String getTipoLimpeza() {
33. return tipoLimpeza;
23
34. }
35. public void setTipoLimpeza(String tipoLimpeza) {
36. this.tipoLimpeza = tipoLimpeza;
37. }
38. public String getVoltagem() {
39. return voltagem;
40. }
41. public void setVoltagem(String voltagem) {
42. this.voltagem = voltagem;
43. }
44. public boolean parar() {
45. return false;
46. }
47. public void mapear() {
48. System.out.println(“Implementar!”);
49. }
50. public void voltarBase() {
51. if(this.verificarBateria()) {
52. System.out.println(“Permitido voltar a 
base!”);
53. }
54. }
55. public boolean ativarSensorColisao() {
56. return false;
57. }
58. private boolean verificarBateria() {
59. return false;
60. }
61. }
Na linha 1, temos a definição de nossa classe. Trata-se de uma classe 
pública, intitulada “Aspirador”. Na sequência, temos os atributos de 
nossa classe. Por padrão, os atributos serão sempre declarados no início 
do corpo da classe. A classe tem um “corpo” que se inicia com a chave 
24
(“{“) e que termina com outra chave (“}”). Este padrão também é utilizado 
na declaração dos métodos, como no método getCor().
Como, por padrão, todos os atributos estão declarados como privados, 
ou seja, possuem restrição de acesso – o que permite que tais atributos 
só possam ser modificados pela própria classe –, é necessário criarmos 
métodos que permitam a outros objetos e classes a alteração ou 
consulta dos valores dos atributos da classe “Aspirador”. Para isso, 
declaramos um conjunto de métodos, os quais, geralmente, são 
chamados de getters e setters.
Enquanto um método get busca ou “pega” algo, um método set configura 
ou altera algo. No caso, o atributo “cor”, por exemplo, para ser alterado 
precisa do método “setCor(String cor)”, declarado da linha 11 até a linha 
13. Este método não possui retorno, por isso, em sua assinatura, temos 
a palavra void, e recebe como atributo uma String, ou seja, uma cadeia 
de caracteres que serão atribuídos para o atributo da classe.
Quando falamos de um retorno do método, indicamos que é 
esperado que, ao final da execução do corpo do método, ou seja, suas 
funcionalidades, o método retorne um resultado. Esse resultado deverá 
ser exatamente do mesmo tipo que foi indicado na sua assinatura. Um 
exemplo de assinatura de método é “public boolean parar()”, declarado 
na linha 44. Neste caso, o método deverá retornar um valor booleano, 
ou seja, verdadeiro (true) ou falso (false). Quando um método tem sua 
assinatura indicando a palavra void entre o tipo de encapsulamento e 
seu nome, indicará que o método não terá retorno. Os métodos que 
exigem retorno precisam ter a palavra return e o dado/informação 
indicados obrigatoriamente. No caso do método da linha 44, o seu 
retorno é indicado na linha 45: “return false;”. Como ainda não temos 
uma implementação completa do método, este será o retorno, se 
executarmos o código.
25
Retornando aos métodos getters e setters, para consultarmos um valor 
de atributo, devemos usar o método getCor(), declarado, por sua vez, da 
linha 8 até a linha 10. Este método tem um retorno – e faz todo sentido 
possuir –, já que retornará o valor do atributo “cor”, que é do tipo String. 
É por isso que temos a palavra String no cabeçalho do método. Da linha 
14 até a linha 43, temos os demais métodos gets e sets. Note que o nome 
de tais métodos é sempre formado pela palavra get ou set, seguida pelo 
nome do atributo com letra maiúscula. Esta é uma boa prática e uma 
padronização para se nomear métodos.
No contexto da nomeação dos atributos, quando algum deles é 
formado por uma ou mais palavras, utilizamos também letra maiúscula 
para iniciar a palavra concatenada. Contudo, um atributo ou método 
sempre iniciará com letra minúscula. Já para o nome da classe, sempre 
utilizaremos a letra maiúscula. Este padrão de nomenclatura é chamado 
CamelCase, que corresponde à denominação, em inglês, para a prática 
de escrever as palavras compostas ou frases, em que cada palavra é 
iniciada com maiúsculas e unidas sem espaços (GUERRA, 2014).
Voltando ao código de nossa classe “Aspirador”, temos outros métodos 
que não estão inseridos no grupo dos métodos de setters e getters. O 
método da linha 44, “parar()”, por exemplo, deve retornar um booleano, 
ou seja, verdadeiro ou falso, mas não temos uma implementação 
do método, apenas um retorno (“return false;”) no seu corpo. Por tal 
método ser público, ele poderá ser chamado por objetos e classes que 
queiram interagir como um objeto instanciado da classe “Aspirador”. O 
método “mapear()”, por exemplo, é do tipo void, ou seja, sem retorno 
e não está implementado também. No seu corpo, há apenas uma 
mensagem, a qual será exibida no terminal quando tal código for 
executado.
Ainda sobre os métodos da classe “Aspirador”, temos o método 
declarado da linha 58 até a linha 60, “verificarBateria()”. Esse método, 
assim como os demais, precisa de alguma implementação de 
26
comportamento em seu corpo, para poder realizar a funcionalidade 
esperada. Contudo, o que nos chama a atenção nesse método é que 
ele é privado, pois está identificado com a palavra private, assim como 
osatributos. Logo, o método está encapsulado, o que implica dizer que 
ele só poderá ser chamado internamente na própria classe. Definir 
um método como privado requer uma análise, em especial, de seu 
comportamento e do que se espera que ele faça. Considerando que ele 
pode alterar algo específico e interno à classe, opta-se por declará-lo 
como privado.
Adicionalmente, a questão de privar ou não o acesso de métodos 
ou atributos está envolvida com a responsabilidade do que se quer 
encapsular e a boa prática de não permitir que outros objetos/classes 
alterem valores de objetos sem a utilização dos devidos métodos criados 
para isso (getters e setters).
Se observarmos o código do método “voltarBase()”, perceberemos 
que, ainda que incompleto, ele faz uma chamada do método 
“verificarBateria()”. Assim, é possível perceber que, por estar dentro 
de uma estrutura condicional if, espera-se que o método retorne 
verdadeiro para que o conteúdo interno ao bloco condicional – no caso, 
o que está declarado na linha 52 – seja executado.
Agora que temos um exemplo claro de como abstrair um objeto do 
mundo real, precisamos de um código adicional para executar nossa 
classe, ainda que seus métodos não estejam todos implementados. 
Para isso, criaremos uma classe chamada “Principal”, a qual permitirá 
executar nossa classe “Aspirador”. Essa classe é apresentada no código a 
seguir:
1. public class Principal {
2. public static void main(String[] args) {
3. Aspirador a = new Aspirador();
4. a.setCor(“Vermelho”);
5. a.setModelo(“Skynet”);
27
6. System.out.println(“A cor do aspirado é: “ + 
a.getCor());
7. System.out.println(“A modelo do aspirado é: “ + 
a.getModelo());
8. }
9. }
Para que nossa classe “Aspirador” pudesse ser executada, criamos uma 
classe que contenha o método “main”. Esse método, que traduzido 
quer dizer “principal”, inicia qualquer programa em Java. No exemplo 
de nosso código, na linha 3, temos a instanciação de um objeto em uma 
variável de referência chamada “a”. Essa variável é do tipo “Aspirador” 
e é instanciada por meio da palavra reservada “new”, seguida pela 
chamada do método construtor da classe. O nome “a” poderia ser 
qualquer nome, mas, ao definirmos, devemos usar o que foi definido em 
todo o restante do código.
O método construtor, sobre o qual falaremos a seguir, apesar de não 
aparecer no código da classe “Aspirador”, é implicitamente criado pelo 
Java para permitir a instância de objetos. Resumidamente, é o método 
construtor responsável por “construir”, ou melhor, instanciar os objetos 
de uma classe concreta.
Na sequência, nas linhas 4 e 5, temos a atribuição de valores para 
os atributos “cor” e “modelo”, respectivamente; nas linhas 6 e 7, a 
impressão de cor e modelo, utilizando os métodos de get de cada 
atributo dentro da chamada “System.out.println()”, que é um método 
que imprime conteúdo no terminal. Se quiséssemos alterar mais 
atributos, bastaria chamarmos os métodos sets respectivos. Poderíamos, 
ainda, criar outras variáveis de referência e, assim, instanciarmos mais 
de um robô aspirador de pó.
Agora, ampliaremos nossos conhecimentos no contexto de herança.
28
2. Herança com Java
Considerando o próprio nome do paradigma – orientação a objetos 
–, temos um elemento essencial e central: o objeto. Como vimos, a 
existência dos objetos só será realizada a partir da instanciação deles. A 
prática, considerando que OO visa ao reuso, é criarmos classes genéricas 
que permitam criar objetos que compartilhem comportamentos e 
propriedades, sendo o conjunto destas últimas chamado de estado. 
Mas, geramos de fato uma classe genérica para instanciar nossos 
aspiradores de pó robô? E se eu quisesse instanciar também aspiradores 
de pó convencionais, seria possível?
A resposta é sim, mas precisamos realizar algumas modificações, como 
considerar aspiradores que possuem alimentação de energia direto 
com tomada e que não voltarão a uma base para recarregar, já que 
não se tratam de robôs autônomos. E como fazer isso? Como podemos 
criar dois tipos de objetos e derivá-los de um modelo comum, já que 
compartilham funcionalidades específicas?
Primeiramente, precisamos nos aprofundar ainda mais no contexto da 
abstração, voltada ao desenvolvimento de software. Com a abstração, 
devemos pensar também no contexto de dividir para conquistar. Muitas 
especificidades podem ser trabalhadas de modo isolado, por exemplo, 
ao pensarmos em um objeto carro, o motor e outras partes são também 
candidatos a se tornarem classes e objetos delas instanciados. Neste 
contexto, temos a adição da modularização (JECK, 2021).
Na modularização, dividimos o todo em partes bem definidas, as 
quais interagem de modo bem definido, tendo, assim, seu papel 
bem identificado. Colocando a abstração e a modularização juntos, 
temos que, enquanto a modularização restringe-se ao processo de 
dividir problemas em partes menores, a abstração é a capacidade de 
ignorar detalhes e focalizar em cenários mais abrangentes (JECK, 2021; 
PRESSMAN; MAXIM, 2021).
29
Deste modo, utilizaremos da herança para permitir modularizar e 
abstrair o que precisamos: instanciar diferentes tipos de aspiradores 
de pó, tanto do tipo robô quanto convencionais. A Figura 2 apresenta 
a separação dos atributos e métodos das classes envolvidas e o 
mecanismo de herança.
Figura 2 – Herança com Classe Aspirador
Fonte: elaborada pelo autor.
A Figura 2 adapta a nossa necessidade para permitir instanciarmos 
objetos do tipo aspirador robô e aspirador vertical. Note que os 
atributos comuns entre os dois tipos de objetos foram mantidos 
na classe pai, e os atributos que eram específicos para cada tipo de 
aspirador foram incluídos nas suas respectivas classes, e ambas herdam 
as características em comum da classe pai.
30
A ideia principal do conceito de herança é permitir a reutilização de 
elementos em comum, retirando a necessidade de se duplicar código 
e permitir estender uma classe de outra (JECK, 2021). Os conceitos de 
superclasse e subclasse correspondem à classe pai, que é superior, 
por isso chamada de superclasse, e à classe filha, intitulada subclasse. 
Poderíamos, se necessário, ter uma outra superclasse, tornando a classe 
“Aspirador” uma classe filha de outra classe e, ao final, a classe “Robo”, 
por exemplo, herdaria as características da classe herdada pela classe 
“Aspirador”, além dos próprios elemento de tal classe.
É importante mencionar que o encapsulamento de elementos da classe 
pai faz com que a classe filha utilize-se de métodos públicos para alterar 
estados ou chamar comportamentos. O que for privado não estará 
disponível para a classe filha. Se o atributo, método ou mesmo classe for 
encapsulado como protected, a classe filha terá acesso total ao elemento 
que assim o for marcada.
Outro detalhe importante, que pode parecer irrelevante a princípio, 
é o fato de nossa classe pai estar com o nome “Aspirador” em itálico. 
Isso indica que a classe é abstrata, ou seja, não conseguiremos 
instanciar um objeto dela, somente das classes concretas (“Robo” e 
“Vertical”). Adicionalmente, podemos ter métodos marcados também 
como abstratos, que deverão ser implementados especificamente nas 
classes filhas, que estenderem à classe “Aspirador”. É o caso do método 
“verificarBateria()”.
Analisaremos, agora, o código de tais classes. Para fins de 
representação, o código dos getters e setters será suprimido, já que o 
vimos no código da classe “Apirador” anteriormente.
Código classe “Aspirador” atualizado, com getters e setters ocultados.
1 public abstract class Aspirador {
2 private String cor;
31
3 private String modelo;
4 private String tipoLimpeza;
5 private String voltagem;
6 private boolean bateria;
7
8 a 46 getters e setters
47
48 public boolean desligar() {
49 System.out.println(“Aparelho desligado!”);
50 return false;
51 }
52
53 public boolean ligar() {
54 System.out.println(“Aparelholigado!”);
55 return true;
56 }
57
58 public abstract boolean verificarBateria();
59
60 }
Código classe “Robo”
1 public class Robo extends Aspirador {
2 private String tipoAplicativo;
3 private String tipoControle;
4 
5 public Robo() {
6 super.setCor(“vermelho”);
7 super.setModelo(“Zyon”);
8 super.setBateria(true);
32
9 super.setTipoLimpeza(“A seco”);
10 super.setVoltagem(“220 voltz”);
11 this.tipoAplicativo = “Android”;
12 this.tipoControle = “Por aplicativo apenas.”;
13 }
14
15 public String getTipoAplicativo() {
16 return tipoAplicativo;
17 }
18
19 public void setTipoAplicativo(String tipoAplicativo) {
20 this.tipoAplicativo = tipoAplicativo;
21 }
22
23 public String getTipoControle() {
24 return tipoControle;
25 }
26
27 public void setTipoControle(String tipoControle) {
28 this.tipoControle = tipoControle;
29 }
30
31 public void mapear() {
32 System.out.println(“Mapeando Ambiente”);
33 }
34
35 public void voltarBase() {
36 if(this.verificarBateria()) {
37 System.out.println(“Voltando a base!”);
33
38 } else {
39 System.out.println(“Não é possível voltar a base, a 
bateria está fraca!”);
40 }
41 }
42
43 public boolean ativarSensorColisao() {
44 return true;
45 }
46
47 @Override
48 public boolean verificarBateria() {
49 if(super.getBateria()) {
50 return true;
51 }else {
52 return false;
53 }
54 }
55
56}
Código classe “Vertical”
1 public class Vertical extends Aspirador {
2 private boolean hasteAjustavel;
3 private float tamanhoCabo;
4 
5 public boolean isHasteAjustavel() {
6 return hasteAjustavel;
7 }
8
34
9 public void setHasteAjustavel(boolean hasteAjustavel) {
10 this.hasteAjustavel = hasteAjustavel;
11 }
12
13 public float getTamanhoCabo() {
14 return tamanhoCabo;
15 }
16
17 public void setTamanhoCabo(float tamanhoCabo) {
18 this.tamanhoCabo = tamanhoCabo;
19 }
20
21 public void recolherCabo() {
22 System.out.println(“O cabo de “ + this.
getTamanhoCabo() + “ foi recolhido!” );
23 }
24
25 @Override
26 public boolean verificarBateria() {
27 if(super.getBateria()) {
28 System.out.println(“Bateria carregada!”);
29 return true;
30 }else {
31 System.out.println(“Bateria fraca!”);
32 return false;
33 }
34 } 
35 }
Classe Principal
35
1. public class Principal {
2. 
3. public static void main(String[] args) {
4. Robo a = new Robo();
5. Vertical v = new Vertical();
6. 
7. System.out.println(“A cor do aspirado é: “ + 
a.getCor());
8. System.out.println(“A modelo do aspirado é: “ + 
a.getModelo());
9. a.ligar();
10. a.desligar();
11. 
12. v.setCor(“Azul”);
13. v.setModelo(“Arnold”);
14. v.ligar();
15. v.desligar();
16. v.verificarBateria();
17. 
18. }
19. 
20. }
A classe “Aspirador” é abstrata, logo não pode ser instanciada. Além 
disso, por ser abstrata, ela pode declarar métodos abstratos, como é o 
caso do método “verificarBateria()” na linha 58. Esse método não pode 
ser chamado e precisa, por polimorfismo, ser implementado nas classes 
que estenderem a classe “Aspirador”. E mesmo sendo abstrata, a classe 
pode continuar tendo métodos com declarações convencionais.
A classe “Robo”, por ser classe filha da classe “Aspirador”, apresenta esta 
herança na primeira linha, em “extends Aspirador”. A palavra reservada 
extends permite às classes filhas estenderem a classe pai desejada. 
Nas linhas 2 e 3, temos a declaração de mais dois atributos além dos já 
36
existentes na classe pai. Da linha 5 até a linha 13, temos a declaração 
explícita do método construtor da classe “Robo”. Esse é o método 
responsável por instanciar objetos de tais classes e que, em muitos 
casos, pode não ser declarado explicitamente.
O método construtor tem uma característica específica: é o único 
método que começa com letra maiúscula, pois deve ser escrito 
exatamente com a mesma grafia do nome da classe. No caso de nossa 
classe “Robo”, o método construtor foi declarado, pois ele modifica 
atributos da classe pai e da classe filha, para permitir instanciar um 
objeto com valores já pré-atribuídos e que poderão, ao longo da 
execução do programa, ter seu estado modificado sem empecilhos.
O uso da palavra “super” para chamar os setters se deve ao fato de os 
atributos, como já mencionado anteriormente, estarem declarados 
como privados. Deste modo, ainda que tenham sido herdados da classe 
pai, precisam ser modificados somente via métodos.
Já a palavra this, utilizada nas linhas 11 e 12, auxilia na identificação de 
que estamos tratando de um atributo ou método, se utilizado junto a 
um método, de elementos da própria classe. No caso, não utilizamos 
o método “setTipoAplicativo()”, por exemplo, para modificar o valor do 
atributo “tipoAplicativo”. Estamos modificando diretamente o valor no 
atributo. O mesmo ocorre com o atributo “tipoControle”.
Um outro trecho de código que requer atenção é a sobrescrita do 
método “verificarBateria()” declarado como abstrato na superclasse 
“Aspirador”. A classe abstrata serve como um contrato que obriga a 
subclasse a implementar os métodos indicados como abstratos. Logo, 
caso um método não seja pertinente de ser implementado, ele ficará 
com o seu corpo vazio, na classe filha, o que não é o caso de nosso 
exemplo, em que o método “verificarBateria()” foi primeiramente 
indicado com a marcação “@Overrride”, sinalizando que está ocorrendo 
uma sobrescrita do método vindo da classe pai.
37
Considerando a sobrescrita, temos a implementação de código no corpo 
do método, determinando o comportamento dele. Ao compararmos 
o mesmo método para a classe “Vertical”, notamos que ele foi 
implementado de modo diferente, e isso é o esperado.
Como temos objetos diferentes, os quais se comportarão de modos 
diferentes, faz sentido termos métodos que serão diferentes entre 
si, mas a assinatura permanecerá a mesma. Deste modo, estamos 
utilizando de mais um pilar de OO, o polimorfismo, que será abordado 
em outros momentos.
Finalmente, para executarmos nosso código, temos a classe “Principal” 
alterada, instanciando dois objetos: “a” do tipo “Robo” e “v” do tipo 
“Vertical”. Note que a chamada dos métodos construtores deles são 
idênticas, mas, no caso da classe “Robo”, temos a declaração explícita 
do método construtor, o que não temos na classe “Vertical”. No entanto, 
como já foi mencionado, o método construtor não declarado é chamado 
implicitamente por Java, pois é ele que permite instanciar os objetos.
Nas linhas 7 a 16 da classe Principal, temos o chamamento dos métodos 
dos objetos instanciados.
Destarte, percorremos novamente os pilares de OO, com ênfase 
na abstração e herança. Vários testes e modificações podem e são 
recomendados serem feitos nos códigos disponibilizados, para que 
o entendimento seja amplo e mais aprofundado. Recomenda-se a 
identificação dos pilares no código e testes específicos com os objetos e 
seus métodos, a fim de permitir uma compreensão mais completa dos 
exemplos dados. Bons estudos!
Referências
38
GUERRA, E. Design Patterns com Java: projeto orientado a objetos guiado por 
padrões. São Paulo, SP: Casa do Código, 2014.
JECK, D. Introduction to programming using Java. Geneva, NY: Hobart and William 
Smith Colleges, 2021.
MICHAELIS. Moderno dicionário da língua portuguesa. São Paulo, SP: Companhia 
Melhoramentos, 1998.
PRESSMAN, R. S.; MAXIM, B. R. Engenharia de software. São Paulo, SP: McGraw Hill 
Brasil, 2021.
39
Encapsulamento e instanciação 
de objetos
Autoria: Anderson da Silva Marcolino
Leitura crítica: FabianoGonçalves dos Santos
Objetivos
• Compreender a instanciação e o encapsulamento de 
classes, pacotes, métodos e atributos em projetos 
orientados a objetos.
• Estabelecer como os métodos construtores podem 
definir o estado do objeto no momento de sua 
instanciação.
• Compreender, via código, como e quando utilizar 
interfaces no lugar de herança com classes abstratas 
e como os objetos instanciados se comunicam entre 
si, considerando a linguagem Java.
40
1. Protegendo elementos na programação 
orientada a objetos
Na programação orientada a objetos (OO), temos diversos recursos, 
e estes são reflexos de seus quatro pilares. Um desses recursos é 
o encapsulamento, por meio do qual podemos privar o acesso de 
determinados elementos em nosso código, como classes, atributos e 
métodos (JECK, 2021).
O termo encapsulamento é chamada de data hidding, em inglês. O 
objetivo, ao restringir o acesso, está associado ao contexto de abstração. 
O usuário ou, no caso do código-fonte, o desenvolvedor não sabe o 
que de fato ocorre dentro do elemento encapsulado, mas, por meio de 
seus métodos, atributos etc., é possível identificar como poderá usar o 
elemento restrito em seu código e como poderá interagir com ele (JECK, 
2021; FURGERI, 2018).
Alguns autores conceituam o encapsulamento como a acessibilidade, já 
que permitirá tornar ou não os elementos restritos em uma classe, ou 
até ela inteira. Dentre as vantagens de seu uso, estão: ocultar detalhes 
do código e do comportamento; aumentar a legibilidade do código; 
reduzir erros de programação; restringir conteúdos de variáveis e 
facilitar novas atualizações (FURGERI, 2018).
Há quatro modificadores de acesso ou qualificadores de acesso, sendo 
eles: public – não aplica nível de restrições; private – apenas a própria 
classe pode ter acesso aos atributos ou variáveis e aos métodos; 
protected – as variáveis e os métodos podem ser acessados pela própria 
classe e suas subclasses, no caso de herança; package-private – a 
classe só pode ser acessada por outras classes no mesmo pacote, é o 
encapsulamento padrão, ao não se utilizar um qualificador (ORACLE, 
2022).
41
Comumente, declaramos os atributos de nossas classes como privados, 
e os métodos para manipularmos os atributos como públicos, os gets e 
sets, os quais assim asseguram que certas variáveis só possam ter seus 
valores alterados via métodos públicos ou a partir da própria classe 
(FURGERI, 2018). Como o encapsulamento envolve também os pacotes 
em Java, consideraremos um exemplo para entender um pouco mais 
sobre tal pilar, sobre os modificadores protected e package-private e 
sobre outros conceitos importantes de Java e OO.
Classe SomarSubtrair
1. package br.com.tema3.operacoesbasicas;
2. 
3. import javax.swing.JOptionPane;
4. 
5. public class SomarSubtrair {
6. 
7. public void SomarESubtrair() {
8. Somar s = new Somar(1);
9. JOptionPane.showMessageDialog(null, “O valor 
 da da soma de dois doubles é: “ + 
 s.somarDoisDoubles(2.4, 2.6));
10. }
11. 
12. }
Classe Somar
1. package br.com.tema3.operacoesbasicas;
2. 
3. public class Somar {
4. 
5. private int valor1;
6. 
42
7. public Somar(int valor1){
8. this.valor1 = valor1;
9. }
10. public Somar(){
11. }
12. 
13. public int somarDoisInteiros(int valor2) {
14. return (this.valor1 + valor2);
15. }
16. 
17. protected double somarDoisDoubles(double valor1, 
 double valor2) {
18. return (valor1 + valor2);
19. }
20. 
21. }
Classe Multiplicar
1. package br.com.tema3.operacoes;
2. 
3. import javax.swing.JOptionPane;
4. 
5. import br.com.tema3.operacoesbasicas.Somar;
6. 
7. public class Multiplicar {
8. protected final float PI = 3.1416f;
9. public static final int CONSTATE = 1;
10. 
11. public double MultiplicarComPI(double valor) {
12. return valor*PI;
13. }
14. 
15. public void SomarEMultiplicar() {
43
16. Somar s = new Somar();
17. //O método somarDoiDoubles não está visível, 
 mesmo importando a classe Somar!
18. //JOptionPane.showMessageDialog(null, 
 “O valoda da soma de dois doubles é: “ + 
 s.somarDoisDoubles(2.4, 2.6));
19. JOptionPane.showMessageDialog(null, 
 “O valor da da soma de dois inteiros é: “ + 
 s.somarDoisInteiros(CONSTATE));
20. }
21. }
22. 
Classe DividirNumeros
1. package br.com.tema3.operacoes;
2. 
3. public class Dividir {
4. 
5. public double DividirNumeros(double valor, 
 double divisor) {
6. return valor/divisor;
7. }
8. 
9. }
Classe Principal
1. package br.com.tema3.main;
2. 
3. import java.text.DecimalFormat;
4. 
5. import br.com.tema3.operacoes.Dividir;
6. import br.com.tema3.operacoes.Multiplicar;
44
7. import br.com.tema3.operacoesbasicas.Somar;
8. import br.com.tema3.operacoesbasicas.SomarSubtrair;
9. 
10. public class Principal {
11. 
12. public static void main(String[] args) {
13. Somar s = new Somar();
14. Somar sn = new Somar(3);
15. SomarSubtrair ss = new SomarSubtrair();
16. Dividir d = new Dividir();
17. Multiplicar m = new Multiplicar();
18. 
19. DecimalFormat formatacao = new DecimalFormat();
20. formatacao.applyPattern(“0,00”); //Se utilizar 
 “#,##” valores de zero serão ocultados
21. 
22. System.out.println(“Resultado da 
 soma de dois inteiros (constante = 1): “ + 
 s.somarDoisInteiros(Multiplicar.CONSTATE));
23. System.out.println(“Resultado da soma de dois 
 inteiros: “ + s.somarDoisInteiros(2));
24. System.out.println(“Resultado da soma de 
 dois inteiros (método construtor recebeu 3): “ 
 + sn.somarDoisInteiros(2));
25. 
26. ss.SomarESubtrair();
27. System.out.println(“Resultado da divisão: “ + 
 d.DividirNumeros(2.4e2, 2.4e2));
28. System.out.println(“Resultado da multiplicação 
por PI: “ + formatacao.format(m.MultiplicarComPI(1.0e2)));
29. m.SomarEMultiplicar();
30. 
31. }
45
32. 
33. }
Considerando o código apresentado e as cinco classes, entenderemos 
os conceitos do encapsulamento e, na sequência, outros conceitos 
fundamentais para se programar em OO com Java.
O código apresentado corresponde a um projeto com três pacotes: 
o pacote br.com.tema3.operacoesbasicas, o pacote br.com.tema3.
operacoes e o pacote br.com.tema3.main. As classes, em projetos Java, 
são mantidas em pacotes. Como padrão de nomenclatura, utiliza-se 
o domínio da empresa ou instituição à qual o projeto será destinado. 
A título de exemplo, usamos o domínio que seria www.tema3.com.br 
para compor o nome dos pacotes que ficaram, seguindo a padronização 
como “br.com.tema3”, sem o “www” e escrito de trás para frente.
Considerando que temos diversos elementos encapsulados, notamos 
que as classes “SomarSubtrair” e “Dividir” contêm todos os seus 
métodos públicos, bem como suas classes. A classe “Somar” apresenta 
um atributo privado que só é modificado quando um novo objeto é 
instanciado e o método construtor, que sofre sobrecarga, é utilizado. 
Falaremos sobre o método construtor mais adiante. Na mesma classe, 
temos, ainda, o método “somarDoisDoubles()”, que é qualificado como 
protected.
Ao indicarmos o encapsulamento como protected, estamos restringindo 
os métodos e atributos para serem acessados pela mesma classe ou 
por subclasses que estejam no mesmo pacote. Ainda que importemos o 
pacote “Somar” em uma classe de outro pacote, não será possível utilizar 
tal método.
A importação de pacotes permite o reuso, visto que podemos utilizar 
métodos de classes específicas emoutras, mas isso dependerá 
exclusivamente de como utilizarmos o encapsulamento. No caso, 
46
como visto, o protected limita o uso do método. Você pode fazer o teste 
retirando as duas barras (“//”) da linha 18, que está comentando o 
código, e tentar executar o projeto. Dependendo do seu ambiente de 
desenvolvimento integrado (IDE)(e.g. Netbeans, Eclipse), seu código não 
será nem executado.
Sobre comentários, é possível criar comentários e uma única linha, 
como visto nas linhas 17 e 18 da classe “Multiplicar”, e em blocos, 
iniciando com barra + asterisco “/*” e terminando o bloco com asterisco 
+ barra “*/”. Há, ainda, o comentário em blocos utilizados pelo JavaDoc, 
que inclui um asterisco a mais no comentário em bloco: “/**” com 
fechamento “*/”.
Voltando à remoção do comentário da linha 17 e tentando executar, 
notaremos que o método “somarDoisDoubles()” ficará grifado em 
vermelho, indicando erro. Na realidade, não se trata de um erro, pois 
encapsulamos o método com protected.
Outra classe que possui encapsulamento é a classe “Multiplicar”, para 
variável estática PI. Ainda na mesma classe, temos uma constante, 
que é declarada com o nome de “CONSTANTE”, apenas para facilitar a 
visualização.
Uma variável declarada como final corresponde a algo que não 
queremos que o valor seja modificado após a sua atribuição, que 
não precisa ser no momento de sua declaração – normalmente, são 
utilizadas dentro dos métodos –, diferentemente do exemplo. Já uma 
constante precisa ser declarada, e o seu valor atribuído no momento de 
sua declaração. Tanto em uma variável final quanto static, o programa 
apresentará erros, se tentar realizar a modificação de seus valores 
durante a execução.
Sobre a nomenclatura de variáveis, estas devem começar com letra, 
caractere de sublinhado (_) ou cifrão ($). Não é permitido iniciar o nome 
47
de uma variável com número. Já as constantes, por padronização, são 
escritas com letras maiúsculas e as palavras se separam com underline.
Voltando ao código, se tentássemos mudar a chamada da CONSTANTE 
pela variável final PI na linha 22 da classe “Principal”, teríamos também 
um erro, visto que tal variável, por estar declarada como protected, só 
poderá ser acessada por classes que estejam dentro do mesmo pacote. 
No exemplo do código, a classe “Dividir” pode acessar a variável PI, sem 
problemas. Para isso, precisará apenas instanciar um objeto da classe 
“Dividir”.
Quanto ao package, ele é utilizado para definir o pacote para o qual as 
classes que ali forem mantidas possam se comunicar, considerando os 
qualificadores para os diversos elementos que estas mantêm. Assim, 
conseguimos entender os conceitos relacionados ao encapsulamento 
e como este pode ser utilizado no contexto da programação em Java 
e em OO. É importante mencionar que há encapsulamento em outras 
linguagens de programação, não sendo algo específico do Java.
Voltando ao nosso código e analisando os outros elementos 
apresentados, vamos nos aprofundar em alguns elementos que 
podemos usar em nossos programas!
2. Métodos construtores, polimorfismo e Java
Ao observarmos mais atentamente o código da classe “Somar”, 
notamos dois métodos construtores com o mesmo nome, porém com 
quantidades de parâmetros diferentes: “Somar(int valor1)” e “Somar()”. O 
método construtor nos permite instanciar um objeto, o qual é chamado 
da linha 13 até a linha 17 para instanciar as demais classes na classe 
‘Principal”.
48
Nem todas as classes que possuem seus objetos instanciados possuem 
a declaração do método construtor, pois esse é implícito. Todavia, isso 
não ocorre com a classe “Somar”. Nela, queremos inicializar o valor da 
variável “valor1”, logo que o objeto de tal classe concreta for instanciado. 
Para isso, incluímos um parâmetro na assinatura do método construtor. 
Adicionalmente, para permitir que executemos a instanciação sem 
a atribuição de um inteiro para a variável “valor1”, temos o método 
construtor convencional, que seria declarado de modo implícito por Java. 
Mas, por que ter dois métodos?
O método com a assinatura na linha 7, na classe “Somar”, é uma 
sobrecarga do método construtor da linha 10, ou seja, está ocorrendo 
um polimorfismo no contexto da assinatura do método e trata-se deum 
polimorfismo de sobrecarga, no qual o objeto usa o mesmo nome do 
método, mas modifica a quantidade de parâmetros.
Se não houvesse a necessidade de permitirmos instanciar um objeto 
sem a atribuição de um valor para a variável “valor1”, poderíamos 
deixar apenas o método das linhas 10 e 11 declarado, ou remover a 
declaração, já que Java garante a declaração do método construtor de 
modo implícito. Em outras palavras, o método construtor existe, só não 
temos o código dele especificado. É o que ocorre com a classe “Dividir”, 
por exemplo.
É importante lembrar sobre a sobrescrita, outro tipo de polimorfismo, 
no qual se mantém a mesma assinatura do método, contudo o seu 
corpo – o que é delimitado entre “{“ e “}” – será diferente. A sobrescrita 
ocorre quando uma classe concreta estende uma classe, ou seja, temos 
a relação de herança, ou a implementa, quando consideramos uma 
interface. Veremos, a seguir, um exemplo considerando herança e 
interfaces. Antes, ainda, precisamos analisar alguns itens específicos do 
código.
49
Na classe “SomarSubtrair”, na linha 9, temos a utilização de um 
elemento proveniente do pacote Swing de Java: “JOptionPane.
showMessageDialog(null, “O valor da da soma de dois doubles 
é: “ + s.somarDoisDoubles(2.4, 2.6)); pacote Swing. A importação 
ocorre na linha 3. O “JOptionPane.showMessageDialog()” cria uma 
caixa de diálogo, a qual servirá para impressão de valores, tal como 
ocorre quando utilizamos o “System.out.println()”, presente na linha 
22, por exemplo, do código da classe “Principal”. A diferença é que, ao 
usarmos o JOptionPane, utilizamos um elemento que cria uma interface 
gráfica comumente utilizada em aplicações. Já a saída do System.out.
println() apresentará o resultado somente no terminal de saída da 
IDE utilizada, não sendo exibida para um usuário final que não estiver 
executando o código diretamente.
O uso do System.out.println() é, ainda, uma boa prática para realizarmos 
pequenos testes no nosso código, saídas etc. No entanto, a migração 
para elementos gráficos presentes no pacote chamado de Swing, em 
Java, é tendência natural no contexto do desenvolvimento de aplicações 
desktop. No código a seguir, além de explorarmos o contexto de 
herança, interfaces e polimorfismos, utilizaremos um outro tipo de 
JOptionPane, capaz de permitir a leitura de dados via teclado.
Interface IBase
1. package br.com.calculos;
2. 
3. public interface IBase {
4. public abstract double Soma(double a, double b);
5. public abstract double Subtracao(double a, double 
b);
6. public abstract double Divisao(double a, double b);
7. public abstract double Multiplicacao(double a, 
double b);
8. }
50
Classe Impressao
1. package br.com.calculos;
2. 
3. import javax.swing.JOptionPane;
4. 
5. public abstract class Impressao {
6. 
7. public void testeImpressao() {
8. JOptionPane.showMessageDialog(null, “Este é um 
teste de impressão do método testeImpressao()!”);
9. }
10. 
11. public abstract void imprimirResultado();
12. }
Classe Nucleo
1. package br.com.calculos;
2. 
3. import javax.swing.JOptionPane;
4. 
5. public class Nucleo extends Impressao implements IBase 
{
6. 
7. @Override
8. public double Soma(double a, double b) {
9. return a + b;
10. }
11. 
12. @Override
13. public double Subtracao(double a, double b) {
14. return a–b;
15. }
51
16. 
17. @Override
18. public double Divisao(double a, double b) {
19. return a / b;
20. }
21. 
22. @Override
23. public double Multiplicacao(double a, double b) {
24. returna * b;
25. }
26. 
27. @Override
28. public void imprimirResultado() {
29. // TODO
30. }
31. 
32. public void calcular() {
33. double a = Double.
parseDouble(JOptionPane.showInputDialog(“Entre com o 
primeiro número:”));
34. double b = Double.
parseDouble(JOptionPane.showInputDialog(“Entre com o 
segundo número:”));
35. Object[] op = {“Soma”, “Subtração”, 
“Divisão”, “Multiplicação”};
36. String tipo = (String) JOptionPane.
showInputDialog(null, “Selecione o cálculo:\n”, “Pesquisa”, 
JOptionPane.PLAIN_MESSAGE, null, op, “Soma”);
37. switch (tipo) {
38. case “Soma”: {
39. JOptionPane.
showMessageDialog(null, “O resultado da soma é: “+ this.
Soma(a, b));
52
40. break;
41. }
42. case “Subtração”: {
43. JOptionPane.
showMessageDialog(null, “O resultado da subtração é: “+ 
this.Subtracao(a, b));
44. break;
45. }
46. case “Divisão”: {
47. JOptionPane.
showMessageDialog(null, “O resultado da divisão é: “+ this.
Divisao(a, b));
48. break;
49. }
50. case “Multiplicação”: {
51. JOptionPane.
showMessageDialog(null, “O resultado da multiplicação é: “+ 
this.Multiplicacao(a, b));
52. break;
53. }
54. default:
55. throw new 
IllegalArgumentException(“Valor inválido: “ + tipo);
56. }
57. }
58. }
Classe Calculadora
1. package br.com.calculadora;
2. 
3. import br.com.calculos.Nucleo;
4. 
5. public class Calculadora {
53
6. 
7. public static void main(String[] args) {
8. Nucleo n = new Nucleo();
9. n.calcular();
10. }
11. }
A interface “IBase” define a base para a implementação dos cálculos. 
Como toda interface, não há métodos implementados, todos são 
especificados com abstratos e possuem apenas suas assinaturas. Logo, a 
classe “Nucleo”, que implementa tal interface, é obrigada a implementar 
todos os métodos ali presentes. Os métodos sobrescritos são anotados 
com a indicação da palavra @Override, ou seja, sobrescrita – como pode 
ser visto na linha 7, por exemplo.
Adicionalmente, a classe “Nucleo” estende, ou seja, é subclasse da classe 
abstrata “Impressao”, que é, por sua vez, superclasse da classe “Nucleo”. 
Nesta superclasse, temos dois métodos: um abstrato, que obrigará a 
sua implementação na classe filha, e um normal. O método tido como 
normal só será chamado, se necessário, pelo objeto instanciado da 
classe filha, no caso, um objeto do tipo “Nucleo”.
É preciso lembrar que Java permite que a herança seja realizada de 
modo hierárquico, sem um limite, mas que uma classe só pode herdar 
de outra classe, ou seja, não há classes múltiplas. Isso se deve ao fato 
de que, ao coincidir nomes de métodos ou atributos entre classes pai, a 
classe filha não saberia qual método ou atributo utilizar, e isso implicaria 
um problema chamado losango da morte. Para resolver isso, foram 
definidas as interfaces, que podem ser implementadas por um número 
ilimitado de classes, e tais classes podem implementar uma ou mais 
interfaces.
54
No código de exemplo, se nossa classe “Nucleo” necessitasse 
implementar mais de uma interface, colocaríamos uma “,” após “IBase” e 
incluiríamos ali a outra interface, e assim por diante.
Ainda no último exemplo de código, temos um novo tipo de 
JOptionPane, o “showInputDialog”, que cria uma caixa de diálogo, na 
qual podemos digitar um texto e este ser armazenado em uma variável. 
Os valores solicitados para o usuário são os números do tipo double, 
que, para isso, precisam ser convertidos pelo método da classe Double, 
como ocorre nas linhas 33 e 34 da classe “Nucleo”.
Na classe “Nucleo”, temos a utilização de uma estrutura de seleção 
chamada Switch, a qual permite que se verifique o valor de uma variável 
em várias opções: se o valor foi igual, no caso, se o tipo de cálculo for 
igual a uma das operações definidas, o código após os dois pontos (“:”) 
será executado e o “break;” finaliza a execução do programa ali. Esta 
estrutura pode ser vista das linhas 37 a 56. Nesta mesma estrutura, 
temos também o que chamamos de um lançamento de exceção, 
presente na linha 55. Nesta mesma linha, temos a exibição de uma 
mensagem de valor inválido, caso o valor digitado pelo usuário seja 
diferente de uma das operações esperadas na estrutura do Switch.
Finalmente, para executarmos nosso programa, temos uma classe 
principal, assim indicada por possuir o método “main()”, que será o 
método a inicializar a execução de nossa aplicação. Dentro desse 
método, temos, então, a instanciação de um objeto do tipo “Nucleo” 
(linha 8), por meio de seu método construtor implícito e a chamada do 
método “calcular()”, que de fato executa toda a aplicação.
Destarte, percorremos os pilares de OO, com ênfase, no primeiro 
código, no encapsulamento, e no segundo, no contexto de herança. 
Utilizamos, ainda, a conversão de valores para Double, a biblioteca 
Swing e estruturas condicionais e de seleção, como o Switch. Há 
outros elementos e recursos da linguagem Java, mas aqueles que 
55
foram apresentados permitem a criação de aplicações iniciais e, em 
especial, compreender o poder de reuso e delimitações mais precisas 
de aplicações orientadas a objetos. Estar atento à documentação oficial 
de Java é fortemente recomendado para que se entenda ainda mais tais 
elementos e se aprendam novos. Bons estudos!
Referências
FURGERI, S. Java 8 Ensino Didático: desenvolvimento e implementação de 
aplicações. São Paulo, SP: Saraiva Educação S.A., 2018.
JECK, D. Introduction to programming using Java. Geneva, NY: Hobart and William 
Smith Colleges, 2021.
ORACLE. Controlling Access to Members of a Class. Oracle, 2022. Disponível em: 
https://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html Acesso em: 
17 fev. 2023.
56
Implementação de interfaces 
gráficas com Java
Autoria: Anderson da Silva Marcolino
Leitura crítica: Fabiano Gonçalves dos Santos
Objetivos
• Compreender a integração de todos os pilares da 
orientação a objetos para a construção de uma 
aplicação com interface gráfica.
• Estabelecer uma estrutura precisa de uma aplicação, 
considerando a utilização de pacote de interface 
gráfica, como Swing, do Java.
• Compreender, via código, a implementação de 
sobrescrita de métodos.
57
1. Primeiros passos com interface gráfica em 
Java
A programação orientada a objetos (OO) é aplicada no desenvolvimento 
de diferentes aplicações e softwares. Para que estas se tornem mais 
robustas e facilitem a utilização aos usuários, adotam-se as interfaces 
gráficas dos usuários. É importante não confundirmos as interfaces, que 
são implementadas por classes concretas com estas interfaces gráficas.
Sempre que vamos nos referenciar a interfaces que refletem um 
contexto visual, utilizaremos o termo “gráfico” junto. Portanto, uma 
interface gráfica é aquilo que será exibido nas telas, nas quais os 
usuários interagirão.
Deste modo, quando utilizarmos interfaces gráficas de usuário em 
Java, aplicamos todos os pilares de tal paradigma: abstração, herança, 
polimorfismo e encapsulamento. Este uso ocorre com bibliotecas 
específicas.
Nas versões mais antigas, Java nos fornecia um pacote para o 
desenvolvimento de interfaces gráficas chamado Abstract Window 
Toolkit (AWT), ou na tradução direta, kit de ferramentas para janelas 
abstratas. Com novas versões, o AWT foi estendido, dando origem a uma 
nova e mais robusta biblioteca, a Swing (JECK, 2021; FURGERI, 2018). 
Atualmente, a Swing está com solicitação de retirada das especificações 
Java, visto que novos arcabouçospara a criação de interfaces gráficas 
estão sendo utilizados, como o JavaFX. Contudo, é importante mencionar 
que o JavaFX pode ser integrado a aplicações Swing já existentes (ORACLE, 
2014).
Considerando que a biblioteca Swing é uma evolução, ela traz benefícios, 
como melhor aparência às interfaces gráficas, melhores tratamentos de 
eventos, recursos, entre outros. Adicionalmente, por ser uma extensão 
58
da AWT, para diferenciar seus elementos, temos a adição do J no nome 
de cada elemento. Por exemplo, para inserirmos um botão no AWT, 
adicionávamos um objeto da Classe Button; com a biblioteca Swing, 
adicionaremos um objeto da Classe JButton (FURGERI, 2018).
Ao falarmos de bibliotecas, aquelas que são mantidas e disponibilizadas 
pela Oracle – a empresa mantenedora de Java – são seguras e são 
importadas automaticamente pelos ambientes de desenvolvimento 
integrados, como Eclipse e NetBeans. Contudo, há também pacotes 
e bibliotecas de terceiros, como versões específicas da Java DataBase 
Connectivity, que, na tradução direta, indica um pacote de conectividade 
Java com banco de dados. Um driver JDBC deverá ser específico para 
o banco que se deseja fazer a conexão, sendo disponibilizado pelas 
empresas mantenedoras de tais bancos de dados. É importante 
mencionar que, ainda que um driver JDBC seja desenvolvido para atuar 
com bancos específicos, ele segue as especificações da Oracle.
O uso de pacotes é essencial para que o reuso ocorra de fato. Ademais, 
para que possamos usá-los, precisamos olhar a documentação dos 
pacotes e das bibliotecas, pois ela nos oferecerá as classes e os métodos 
– em especial, as interfaces – que podemos utilizar em nossos projetos, 
bem como informações adicionais para nos ajudar a explorar, de modo 
mais fácil, todo o potencial dos pacotes utilizados. Deste modo, os 
exemplos que serão apresentados do uso do Swing servirão de base 
para a utilização de outras bibliotecas, mas devemos levar em conta 
a documentação de cada uma delas. É importante frisar que nem o 
mais experiente dos desenvolvedores Java saberão todos os métodos e 
pacotes existentes, por isso é mais importante termos fontes confiáveis 
para pesquisa do que tentar decorar tais mecanismos.
Retornando à nossa biblioteca Swing, é por meio dela que criaremos 
as interfaces gráficas de usuário (GUI), do inglês graphical user interface. 
Quando estamos pensando na criação de uma aplicação com interfaces 
gráficas, um bom planejamento é necessário. Quando em uma 
59
empresa de grande porte, haverá uma equipe com designers gráficos e 
especialistas em experiência de usuário (UX), do inglês user experience, 
para auxiliar na criação dessas interfaces gráficas.
Em projetos menores, podemos nos basear nas interfaces que vemos 
nos sistemas operacionais e em aplicações mais atuais. Isso garantirá 
uma maior aproximação da solução a ser desenvolvida com o que 
os usuários comumente usam. Essa prática garantirá uma melhor 
experiência de quem usará nosso software e maior garantia de que 
estamos criando um projeto bom.
No contexto de Java, ao construirmos nossas interfaces ou uma 
aplicação que possua uma GUI, deveremos seguir alguns passos:
• Definir um desenho inicial ou um esboço do que pretendermos 
desenvolver no contexto da interface – e isso não retira a 
necessidade de se analisar e conceber todo o projeto da 
arquitetura de software.
• Identificar e definir quais componentes (classes e objetos) serão 
utilizados em cada componente desenhado.
• Importar o pacote para o projeto (import javax.swing.* e import 
java.awt.event.*).
• Definir a disposição de tais elementos em tela.
• Programar os comportamentos dos componentes, por meio do 
controle de eventos.
Apesar de utilizarmos o Swing para que os eventos ocorram por meio 
de tais componentes, deveremos importar o pacote de eventos da 
biblioteca AWT. Adicionalmente, como o Swing é uma evolução de 
elementos do AWT, em alguns projetos precisaremos importar e utilizar 
o pacote AWT: import java.awt.*. Em um contexto geral, quando 
60
queremos importar todas as classes que estão dentro de um pacote 
Java, podemos utilizar o asterisco “*”. Se queremos importar alguma 
classe específica, esta poderá ser escrita substituindo o “*”, mas, neste 
caso, ao identificarmos a necessidade de importar mais uma classe – e 
seu componente –, teremos de inserir uma nova linha de importação 
ou substituir a classe que havíamos importado anteriormente, por 
asterisco, reduzindo a quantidade de linhas de importação no cabeçalho 
de nossas classes no projeto.
A Figura 1 apresenta uma interface de aplicação Java. Para a criação de 
GUIs como esta, podemos utilizar algumas ferramentas para facilitar a 
criação, como o editor de Design do NetBeans, que permite arrastar e 
soltar componentes e, assim, “montar” nossa tela como desejado.
Figura 1 – Tela da aplicação
Fonte: elaborada pelo autor.
Na GUI da Figura 1, notamos que a aplicação deve calcular o índice 
de massa corporal (IMC). Para isso, precisaremos que o usuário digite 
o peso, a altura e, depois, clique no botão Calcular. O resultado será 
exibido na caixa de texto que não permite edição. O botão Limpar 
servirá para limpar os campos, para que um novo cálculo possa ser 
realizado. Adicionalmente, uma imagem aleatória pode ser inserida para 
61
deixar a interface mais atrativa, como é o caso do desenho utilizado, que 
indica uma pessoa com massa corpórea elevada e outra baixa, já que 
nosso aplicativo faz, justamente, o cálculo do IMC.
Deste modo, considerando nossa interface, podemos identificar os 
elementos que poderemos utilizar do Swing.
2. Criando nossa aplicação com os 
componentes do Swing
O primeiro elemento a ser criado para que possamos montar nossas 
telas é o JFrame. Ele permite a criação de uma janela com barra de 
títulos, bordas e permite inserir outros elementos em seu interior para 
exibição. Dentre estes itens, um muito utilizado são os JPanels. Como 
o nome sugere, trata-se de um painel que pode, assim como o JFrame, 
receber outros elementos. Deste modo, poderíamos criar em um 
projeto apenas um JFrame e todas as outras interfaces de usuário serem 
montadas em painéis, sendo chamadas ou ocultadas de acordo com a 
navegação do usuário.
Uma outra questão importante ao usarmos JFrame e JPanels são os 
layouts que ajudam a posicionar os elementos. Diversas classes do AWT 
e do Swing oferecem gerenciadores de layout para auxiliar a posicionar 
os elementos na tela, a compor nossas GUIs. Alguns dos mais utilizados 
são o AbsoluteLayout, BorderLayout, BoxLayout, CardLayout, FlowLayout, 
GridBagLayout, GridLayout, GroupLayout e SpringLayout.
Dentre estes, podemos destacar o AbsoluteLayout, BorderLayout, o 
FlowLayout e o GroupLayout. No AbsoluteLayout, nossos objetos ficarão 
na posição em que forem designados, necessitando de valores para 
um posicionamento horizontal e vertical. Os demais layouts seguem 
62
uma direção inicial para posicionar os elementos, com exceção do 
GroupLayout.
O GroupLayout foi criado para auxiliar na criação de GUIs via ferramenta 
de construção de interfaces gráficas, como a existente no NetBeans 
e em plug-ins no Eclipse, Visual Studio Code e outros. Claro que se 
pode utilizá-lo para posicionar elementos de modo manual, contudo a 
especificidade para o posicionamento dos elementos é mais complexa, 
visto que ele trata o posicionamento considerando um layout horizontal 
e outro vertical. A Figura 2 apresenta a tela com a ferramenta de 
construção gráfica do NetBeans em uma interface com GridBagLayot.
Figura 2 – Ferramenta de criação de GUI no NetBeans
Fonte: captura de tela de Apache NetBeans IDE 13.
O Quadro 1 apresenta os principais componentes (classes e seus 
objetos) utilizados em projetos com Swing. É importante destacar 
que estes são somente alguns dos existentes e que se faz necessário 
consultar a documentação de Java, para que possa identificar outros 
possíveis componentes.
63
Quadro 1 – Métodos mais comuns dosprincipais 
componentes do Swing
Componente Método Função
JLabel
JLabel() Cria um rótulo (label) sem texto.
JLabel(String, Image, int) Cria um rótulo (label) com um texto, uma 
imagem e o alinhamento dos dados.
JTextField
JTextField() Cria uma caixa de texto sem conteúdo.
setEditable(boolean)
Ao receber um valor boleano (true ou false), 
indicará se o JTextField será (true) ou não 
(false) editável.
getText() Retorna o valor inserido no campo.
setText() Atribui um valor para o campo.
JButton
Button(String) Cria um botão com texto.
setEnabled(booblean) Recebe um valor para ativar (true) ou desati-
var (false) o botão.
JOptionPane showMessageDialog(Componente, 
String, String, int )
Cria uma caixa de diálogo com a indicação 
do componente que o criou (geralmente, usa-
do a palavra this), a mensagem a ser exibida, 
o texto da barra de títulos e o tipo de mensa-
gem (JOptionPane.INFORMATION_MESSA-
GE, por exemplo).
Fonte: adaptado de Jeck (2021) e Furgeri (2018).
Com base nestes elementos, criaremos nossa tela seguindo o 
modelo especificado na Figura 1. Para isso, usaremos a ferramenta 
de construção de telas do NetBeans, apresentada na Figura 2. Para 
conseguirmos utilizá-la, devemos iniciar um projeto no NetBeans e 
adicionar, no pacote principal, um novo “JFrame Form..”, que criará um 
JFrame e abrirá o NetBeans diretamente na tela de criação de GUIs, 
indicado pela aba “Design”. Para podermos editar e incluir código, 
devemos selecionar a opção “Source”, que corresponde ao código.
Todos os projetos que utilizam tal ferramenta apresentam uma parte do 
código destacada em cor cinza no editor de código. Logo perceberá que 
64
tal texto não pode ser modificado, isso porque este código foi gerado 
pelo NetBeans, por meio do uso da ferramenta de criação da interface 
gráfica. Há a possibilidade de alterarmos estruturas específicas, em 
especial, métodos de eventos dos elementos gráficos que inserirmos, 
por isso, o código a seguir apresenta somente os trechos editáveis.
Antes de começarmos a modificar o código, precisamos inserir, via 
“Palette”, também visualizada na Figura 2, no canto superior direito, 
os seguintes componentes: três JTexfFields (estarão identificados na 
ferramenta como “Text Field” sem o J, mas, ao criarmos o componente, 
como já mencionado, será exibido o J para diferenciar o pacote Swing 
do AWT; adicionalmente, as palavras não terão espaços, pois estamos 
nos referindo a objetos Java); dois botões (identificados como “Button”); 
três labels (identificados por “Label”) e, opcionalmente, uma imagem, 
que será também um componente modificado do tipo “Label”. Após a 
inserção destes elementos, poderemos fazer as modificações no código, 
gerando a aplicação com o código apresentado a seguir.
Código da Classe TelaPrincipal
1. package br.aula.imc_swing;
2. 
3. import java.awt.Color;
4. import java.awt.Container;
5. import java.awt.Dimension;
6. import java.awt.FlowLayout;
7. import java.awt.Toolkit;
8. import javax.swing.JButton;
9. import javax.swing.JDialog;
10. import javax.swing.JLabel;
11. import javax.swing.JOptionPane;
12. import javax.swing.JPanel;
13. import javax.swing.SwingConstants;
14. 
65
15. public class TelaPrincipal extends javax.swing.JFrame 
{
16. 
17. public TelaPrincipal(){
18. initComponents();
19. }
20. 
21. float peso, altura, imc;
22. JDialog dialog;
23. 
24. private void initComponents() {
25. java.awt.GridBagConstraints gridBagConstraints;
26. 
27. jLabel4 = new javax.swing.JLabel();
28. jLabel1 = new javax.swing.JLabel();
29. tfPeso = new javax.swing.JTextField();
30. jLabel2 = new javax.swing.JLabel();
31. tfAltura = new javax.swing.JTextField();
32. jLabel3 = new javax.swing.JLabel();
33. tfResultado = new javax.swing.JTextField();
34. btnLimpar = new javax.swing.JButton();
35. btnCalcular = new javax.swing.JButton();
36. 
37. jLabel4.setText(“jLabel4”);
38. 
39. 
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_
ON_CLOSE);
40. setTitle(“Calculadora de IMC”);
41. getContentPane().setLayout(new java.awt.
GridBagLayout());
42. 
43. jLabel1.setLabelFor(tfPeso);
66
44. jLabel1.setText(“Peso:”);
45. 4gridBagConstraints = new java.awt.
GridBagConstraints();
46. gridBagConstraints.gridx = 2;
47. gridBagConstraints.gridy = 0;
48. gridBagConstraints.gridwidth = 2;
49. gridBagConstraints.ipadx = 34;
50. gridBagConstraints.anchor = java.awt.
GridBagConstraints.NORTHWEST;
51. gridBagConstraints.insets = new java.awt.Insets(24, 6, 
0, 0);
52. getContentPane().add(jLabel1, gridBagConstraints);
53. gridBagConstraints = new java.awt.
GridBagConstraints();
54. gridBagConstraints.gridx = 5;
55. gridBagConstraints.gridy = 0;
56. gridBagConstraints.gridwidth = 6;
57. gridBagConstraints.gridheight = 2;
58. gridBagConstraints.ipadx = 59;
59. gridBagConstraints.anchor = java.awt.
GridBagConstraints.NORTHWEST;
60. gridBagConstraints.insets = new java.awt.Insets(21, 4, 
0, 18);
61. getContentPane().add(tfPeso, gridBagConstraints);
62. 
63. jLabel2.setLabelFor(tfAltura);
64. jLabel2.setText(“Altura:”);
65. gridBagConstraints = new java.awt.
GridBagConstraints();
66. gridBagConstraints.gridx = 2;
67. gridBagConstraints.gridy = 2;
68. gridBagConstraints.anchor = java.awt.
GridBagConstraints.NORTHWEST;
67
69. gridBagConstraints.insets = new java.awt.Insets(11, 6, 
0, 0);
70. getContentPane().add(jLabel2, gridBagConstraints);
71. gridBagConstraints = new java.awt.
GridBagConstraints();
72. gridBagConstraints.gridx = 5;
73. gridBagConstraints.gridy = 2;
74. gridBagConstraints.gridwidth = 6;
75. gridBagConstraints.gridheight = 2;
76. gridBagConstraints.ipadx = 59;
77. gridBagConstraints.anchor = java.awt.
GridBagConstraints.NORTHWEST;
78. gridBagConstraints.insets = new java.awt.Insets(11, 4, 0, 
18);
79. getContentPane().add(tfAltura, gridBagConstraints);
80. 
81. jLabel3.setLabelFor(tfResultado);
82. jLabel3.setText(“Resultado:”);
83. gridBagConstraints = new java.awt.
GridBagConstraints();
84. gridBagConstraints.gridx = 2;
85. gridBagConstraints.gridy = 4;
86. gridBagConstraints.gridwidth = 3;
87. gridBagConstraints.ipadx = 23;
88. gridBagConstraints.anchor = java.awt.
GridBagConstraints.NORTHWEST;
89. gridBagConstraints.insets = new java.awt.Insets(28, 6, 
0, 0);
90. getContentPane().add(jLabel3, gridBagConstraints);
91. 
92. tfResultado.setEditable(false);
93. 
tfResultado.setHorizontalAlignment(javax.swing.JTextField.
TRAILING);
68
94. gridBagConstraints = new java.awt.
GridBagConstraints();
95. gridBagConstraints.gridx = 5;
96. gridBagConstraints.gridy = 4;
97. gridBagConstraints.gridwidth = 5;
98. gridBagConstraints.gridheight = 2;
99. gridBagConstraints.ipadx = 57;
100. gridBagConstraints.anchor = java.awt.
GridBagConstraints.NORTHWEST;
101. gridBagConstraints.insets = new java.awt.Insets(25, 4, 
0, 0);
102. getContentPane().add(tfResultado, gridBagConstraints);
103. 
104. btnLimpar.setText(“Limpar”);
105. btnLimpar.addActionListener(new java.awt.event.
ActionListener() {
106. public void actionPerformed(java.awt.event.
ActionEvent evt) {
107. btnLimparActionPerformed(evt);
108. }
109. });
110. gridBagConstraints = new java.awt.
GridBagConstraints();
111. gridBagConstraints.gridx = 2;
112. gridBagConstraints.gridy = 7;
113. gridBagConstraints.gridwidth = 4;
114. gridBagConstraints.anchor = java.awt.
GridBagConstraints.NORTHWEST;
115. gridBagConstraints.insets = new java.awt.Insets(11, 
36, 17, 0);
116. getContentPane().add(btnLimpar, gridBagConstraints);
117. 
btnLimpar.getAccessibleContext().
setAccessibleName(“btnLimpar”);
69
118. 
119. btnCalcular.setText(“Calcular”);
120. btnCalcular.addActionListener(newjava.awt.event.
ActionListener() {
121. public void actionPerformed(java.awt.
event.ActionEvent evt) {
122. btnCalcularActionPerformed(evt);
123. }
124. });
125. gridBagConstraints = new java.awt.
GridBagConstraints();
126. gridBagConstraints.gridx = 0;
127. gridBagConstraints.gridy = 7;
128. gridBagConstraints.gridwidth = 2;
129. gridBagConstraints.anchor = java.awt.
GridBagConstraints.NORTHWEST;
130. gridBagConstraints.insets = new java.awt.Insets(11, 
103, 17, 0);
131. getContentPane().add(btnCalcular, gridBagConstraints);
132. btnCalcular.getAccessibleContext().
setAccessibleName(“btnCalcular”);
133. 
134. pack();
135. }
136. private void btnCalcularActionPerformed(java.awt.event.
ActionEvent evt) {
137. if(!(tfPeso.getText().isEmpty() || 
tfAltura.getText().isEmpty())){
138. peso = Float.parseFloat(tfPeso.
getText().replace(“,” , “.”));
139. altura = Float.
parseFloat(tfAltura.getText().replace(“,” , “.”));
140. imc = peso / (altura * altura);
70
141. tfResultado.setText(String.valueOf(imc));
142. } else {
143. mensagemDialogo(“Campos em branco. Por 
favor informe!”, “Erro”);
144. //mensagemDialogoCriado();
145. }
146. 
147. }
148. 
149. private void mensagemDialogo(String mensagem, 
String titulo){
150. JOptionPane.showMessageDialog(this, mensagem,
151. titulo, JOptionPane.INFORMATION_MESSAGE);
152. }
153. 
154. private void mensagemDialogoCriado(){
155. //Aqui vamos configurar, de fato o JDialog
156. dialog.setResizable(false);
157. dialog.getContentPane().add(this.createPane());
158. dialog.pack();
159. dialog.setSize(300, 200);
160. Dimension size = Toolkit.getDefaultToolkit().
getScreenSize();
161. dialog.setLocation(new Double((size.
getWidth()/2)–(dialog.getWidth()/2)).intValue(),
162. new Double((size.getHeight()/2)–(dialog.
getHeight()/2)).intValue());
163. dialog.setVisible(true);
164. }
165. 
166. protected Container createPane(){
167. JPanel telaDialogo = new JPanel();
168. telaDialogo.setLayout(new FlowLayout());
71
169. JLabel lbl = new JLabel(“Campos em branco. Por 
favor informe!”, SwingConstants.CENTER);
170. JButton jb = new JButton(“Ok”);
171. jb.addActionListener(e -> telaDialogo.
setVisible(false));
172. telaDialogo.setBackground(Color.GREEN);
173. telaDialogo.add(lbl);
174. telaDialogo.add(jb);
175. return telaDialogo;
176. }
177. 
178. private void btnLimparActionPerformed(java.awt.event.
ActionEvent evt) {
179. tfPeso.setText(“”);
180. tfAltura.setText(“”);
181. tfResultado.setText(“”);
182. }
183. 
184. public static void main(String args[]) {
185. java.awt.EventQueue.invokeLater(new Runnable() {
186. public void run() {
187. new TelaPrincipal().setVisible(true);
188. }
189. });
190. }
191. 
192. // Variables declaration–do not modify
193. private javax.swing.JButton btnCalcular;
194. private javax.swing.JButton btnLimpar;
195. private javax.swing.JLabel jLabel1;
196. 1private javax.swing.JLabel jLabel2;
197. private javax.swing.JLabel jLabel3;
198. private javax.swing.JLabel jLabel4;
72
199. private javax.swing.JTextField tfAltura;
200. private javax.swing.JTextField tfPeso;
201. 2private javax.swing.JTextField tfResultado;
202. // End of variables declaration
203. }
Na linha 1, temos a indicação do pacote onde nossa classe está 
localizada. Da linha 3 até a linha 13, temos a importação dos elementos 
utilizados na nossa aplicação e, na linha 15, temos o início de nossa 
classe, a qual, por ser um JFrame, faz herança da classe javax.swing.
JFrame.
Na linha 17, temos a declaração de um método que se chama 
initComponents(), que, como o nome sugere, chama o método 
declarado a partir da linha 24 até a linha 135, e que, por estar destacado 
em cinza, indica que o código foi gerado automaticamente pelo 
NetBeans. Este método é implementado obrigatoriamente pelas classes 
que implementam a classe JFrame. Assim, trata-se de uma sobrescrita 
de método.
A aplicação de cálculo do IMC, após a entrada das informações pelos 
usuários, ocorrerá no método btnCalcularActionPerformed(java.awt.
event.ActionEvent evt)). Este método é o que chamamos de um evento, 
uma ação realizada, da tradução do termo ActionPerformed pelo 
elemento que recebeu uma interação. No caso, o JButton, que recebeu 
o nome de btnCalcular. Note que nossos JTextFields foram renomeados 
também, usando nomes mais fáceis de serem lembrados para se 
trabalhar no código.
No método da ação do btnCalcular, que vai da linha 136 até a linha 147, 
temos uma estrutura condicional (“if”) que busca validar os campos 
de peso (tfPeso) e altura (tfAltura), identificando se estão vazios. Não 
estando vazios, segue para o cálculo do IMC, que é armazenado em uma 
variável chamada imc e, depois, é convertida em String, na linha 141, 
73
e atribuída ao JTextField txResultado, que exibe o resultado; se algum 
dos campos estiver vazio, segue para o bloco do “senão” (else), que 
exibe uma caixa de diálogo, cujo método é implementado da linha 149 
até a linha 152. Na linha 144, temos uma alternativa para esta caixa de 
diálogo, na qual uma caixa é criada no método definido da linha 154 até 
a linha 164.
O método mensagemDialogoCriado() utiliza um método específico para 
criar um container, via método privado, declarado da linha 166 até 
a linha 176. Este método é privado, pois não deve ser chamado pelo 
objeto instanciado, e sim somente pelos métodos da própria classe, 
exemplificando o uso do encapsulamento.
Da linha 178 até a linha 182, temos a definição de nosso método 
que limpa nossos campos de texto. Tal ação está vinculada ao nosso 
segundo botão, intitulado btnLImpar. Note que, no corpo do método, 
se utiliza o método setText(), para cada um dos JTextFields, para inserir 
um texto vazio, limpando o texto que o usuário possa ter inserido nos 
campos de texto ativos.
Finalmente, na linha 184, temos o método main(), que inicia nossa 
aplicação, e da linha 193 até a linha 201, a declaração das variáveis de 
referência para todos os objetos do Swing utilizados no projeto de nossa 
interface.
Destarte, percorremos os pilares de OO no contexto prático, com o 
uso da biblioteca Swing. Há, ainda, outros elementos e recursos da 
linguagem Java. Todavia, os apresentados permitem a criação de 
aplicações iniciais e, em especial, compreender o poder de reuso e 
delimitações mais precisas de aplicações orientadas a objetos. Estar 
atento à documentação oficial de Java é fortemente recomendado 
para que se entenda mais tais elementos e se aprendam novos. Bons 
estudos!
74
Referências
FURGERI, S. Java 8 Ensino Didático: desenvolvimento e implementação de 
aplicações. São Paulo, SP: Saraiva Educação S.A., 2018.
JECK, D. Introduction to programming using Java. Geneva, NY: Hobart and William 
Smith Colleges, 2021.
ORACLE. JavaFX: Interoperability. Oracle, 2014. Disponível em: https://docs.oracle.
com/javase/8/javafx/interoperability-tutorial/swing-fx-interoperability.htm. Acesso 
em: 28 fev. 2023.
75
BONS ESTUDOS!
	Sumário
	Apresentação da disciplina
	Histórico e pilares da programação orientada a objetos
	Objetivos
	1. Introdução e histórico do paradigma de programação orientada a objetos
	2. Conceitos essenciais de OO 
	Referências 
	Abstração e herança em orientação a objetos
	Objetivos
	1. Abstraindo o mundo real 
	2. Herança com Java 
	Referências 
	Encapsulamento e instanciação de objetos
	Objetivos
	1. Protegendo elementosna programação orientada a objetos
	2. Métodos construtores, polimorfismo e Java 
	Referências 
	Implementação de interfaces gráficas com Java
	Objetivos
	1. Primeiros passos com interface gráfica em Java
	2. Criando nossa aplicação com os componentes do Swing
	Referências

Mais conteúdos dessa disciplina