Buscar

Java Paradigmas

Prévia do material em texto

1 
Conceito de classe, características (atributos), 
Ações (métodos) e construtores 
 
 
 Na Programação Orientada a Objetos (POO) um projeto de 
sistema não está centrado na identificação de 
procedimentos, como na programação estruturada, mas sim na 
identificação de objetos. A partir da identificação dos 
elementos do mundo real, envolvidos com o problema, é que 
são realizadas as demais tarefas. Três das principais 
atividades envolvidas em um projeto orientado a objetos são 
as seguintes: 
 
1. Identificação dos objetos envolvidos com o sistema a 
ser desenvolvido e sua representação em forma de 
classes; 
2. Identificação de suas características relevantes e 
sua representação em forma de atributos; 
3. Identificação de ações (comportamentos) realizadas 
por esses objetos e sua representação em forma de 
métodos. 
 
 Para compreender a POO é preciso analisar o 
significado de diversos elementos. Inicialmente, deve-se 
compreender o significado de objetos e classes. Mas, para 
compreendê-los, também será necessário analisar o conceito 
de atributos e de métodos. 
 
 
Objeto 
 
 Objeto é qualquer entidade do mundo real que apresente 
algum significado, mesmo que tal entidade não se constitua 
em algo concreto. 
 
 Exemplos de objetos do mundo real: Uma mesa, uma 
cadeira, um gato, um cachorro, um computador, uma caneta, 
um disquete, um caderno, um carro, um avião, o Sol, a lua, 
uma estrela, uma nuvem, um pássaro, uma árvore e etc. 
 
 Todo objeto possui algumas características próprias, 
também chamadas de atributos. Esses atributos são as 
qualidades que permitem distinguir um objeto de outros 
objetos semelhantes. Por exemplo: É possível distinguir um 
cachorro dos outros em função de vários atributos: cor, 
raça, altura, comprimento, peso e etc. Do mesmo modo, é 
possível distinguir um carro dos outros em função de um 
conjunto de atributos: marca, modelo, ano, cor, placa, 
chassi e etc. 
 
 2 
 Pode haver dois ou mais objetos que possuam alguns 
atributos com os mesmos valores. Entretanto, em função de 
sua própria natureza, os valores de alguns outros atributos 
são únicos e não se repetem entre os diversos objetos 
semelhantes. Por exemplo: Existe uma infinidade de carros 
cuja cor é vermelha, mas não pode haver dois carros com a 
mesma placa ou chassi. 
 
 Além de possuir atributos, os objetos também 
manifestam um comportamento. O comportamento dos objetos 
diz respeito às ações que eles podem realizar. O cachorro 
pode correr, pular, latir e etc. O computador pode ligar-
se, desligar-se, processar dados, exibir informações no 
vídeo, imprimir textos, emitir sons e etc. 
 
 
Classe 
 
 Na POO, o mais importante não é a identificação dos 
objetos existentes no mundo real. O que realmente importa é 
a identificação de grupos de objetos com atributos e 
comportamentos comuns. Ter atributos e comportamentos 
comuns não significa serem iguais. Apesar de todos os 
cachorros possuírem uma cor, raça, altura, comprimento e 
peso, dois cachorros podem ser bem diferentes por possuírem 
diferentes valores em cada um desses atributos. Um deles 
pode ser preto e o outro branco, um pode ter 90cm de altura 
e o outro ter apenas 70cm e assim por diante. 
 
 Quando um conjunto de objetos possui atributos e 
comportamentos comuns, significa que eles pertencem a uma 
mesma categoria. Se João e Maria são dois clientes de uma 
empresa, pode-se dizer que, apesar de eles serem pessoas 
distintas, pertencem a uma mesma categoria: a dos clientes. 
 
 O termo classe é utilizado para significar o mesmo que 
categoria. Ao invés de dizer que João e Maria pertencem à 
categoria dos clientes, pode-se dizer que eles pertencem à 
classe dos clientes. 
 
 Uma classe representa um grupo de objetos com 
características e comportamentos comuns e compõem-se, 
basicamente, de atributos e métodos. Os atributos 
representam as características dos objetos, e os métodos 
representam as ações ou comportamentos que eles podem 
realizar. 
 
 
 
 
 
 3 
Diferença entre Classe, Objeto e o instanciamento 
a partir do construtor 
 
 
 Objeto: É a instância de uma classe. Ou seja, uma 
variável do tipo de dado definido pela classe. Possuem 
características (atributos) comportamentos (métodos). 
 
 Objetos do mundo real possuem características e 
comportamentos. Já objetos de software armazenam suas 
características em atributos (variáveis) e implementam seus 
comportamentos em métodos 
 
Exemplo: 
 Pessoa joao = new Pessoa(); 
 joao.idade = 30; 
 joao.andar(); 
 
 João é uma variável (objeto) do tipo da classe Pessoa. 
 Idade é um atributo (característica) do objeto João. 
 Andar é um método (comportamento) do objeto João. 
 
 
 Classe: Representa a abstração de uma entidade 
(objeto) do mundo real. A Classe define as características 
e os comportamentos desta entidade (objeto) do mundo real. 
As características são os atributos e os comportamentos são 
os métodos. 
 
 A classe estabelece o formato dos objetos, portanto 
define um tipo de dado. É a representação de um conjunto de 
objetos que compartilham as mesmas características e 
comportamentos. 
 
Exemplo: 
 
public class Pessoa{ 
 String nome; 
 int idade; 
 String endereco; 
 
 public void andar(){ 
 } 
 
 public void informarIdade(){ 
 } 
} 
 
 João e Maria são objetos da classe Pessoa, pois 
compartilham os mesmos atributos (características) e 
métodos (comportamentos). 
 
 4 
Instanciação 
 
 Instanciar uma classe significa criar um novo objeto a 
partir dela própria. Do mesmo modo que toda variável é de 
determinado tipo primitivo, todo objeto pertence a uma 
classe. 
 
 Assim como uma variável precisa ser declarada e 
iniciada, todo objeto precisa ser declarado e instanciado. 
A declaração de um objeto é muito parecida com a declaração 
de uma variável, mas o tipo do objeto será sempre uma 
classe ao invés de um tipo primitivo. 
 
Sintaxe para declaração de um objeto: 
 
 <Classe> <nomeDoObjeto>; 
 
Exemplo para declaração de objeto: 
 
 String str; 
 
 Depois de declarado, todo objeto precisa ser 
instanciado. A instanciação de um objeto consiste, 
basicamente, na alocação de um espaço na memória para que 
ele possa ser representado. 
 
Sintaxe para instanciar um objeto: 
 
 <nomeDoObjeto> = new <construtor>([argumentos]); 
 
 
Método Construtor 
 
 O responsável pela instanciação de um objeto sempre 
será um método construtor disponível em sua classe. Todo 
construtor possui o mesmo nome da classe a que se refere e 
há um construtor padrão na maioria das classes que dispensa 
o uso de argumentos. Toda classe tem, pelo menos, um 
construtor que o compilador adiciona, quando nenhum for 
declarado (construtor default). 
 
 A instanciação é feita através de uma operação de 
atribuição em que o objeto recebe o espaço na memória que 
lhe for reservado pelo construtor. O operador new sempre 
precederá o construtor utilizado nessa operação. Caso seja 
utilizado o construtor padrão (default), o nome do 
construtor será seguido de um par de parênteses sem nada 
dentro, uma vez que ele não exige nenhum argumento. 
 
 
 
 5 
Exemplo para instanciar um objeto: 
 
 Str = new String(); 
 
Além disso, também é possível declarar e instanciar um 
objeto em uma única instrução. Veja a sintaxe abaixo: 
 
 <Classe> <nomeDoObjeto> = new <construtor>([argumentos]); 
 
Veja o exemplo: 
 
 String str = new String(); 
 
 
 Além de exercerem um papel essencial no processo de 
instanciação de classes, os construtores também são 
utilizados para iniciar os atributos com valores padrão ou 
com valores informados. Os construtores são métodos 
especiais que são invocados em conjunto com o operadornew 
para reservar espaço na memória do computador a ser ocupado 
por um novo objeto. 
 
 Algumas classes possuem um construtor padrão que é 
eficaz para a criação de objetos. Entretanto, é possível 
substituir esse construtor padrão por outro diferente, 
definindo-se parâmetros e adicionando-se quaisquer tipos de 
instruções que deseje que sejam executadas sempre que um 
novo objeto for criado. 
 
Sintaxe para a criação de um método construtor: 
 
public <nome> ([<parâmetros>]){ 
 
} 
 
 A sintaxe para implementação de um construtor se 
assemelha à de um método qualquer. No entanto, em uma 
análise mais detalhada, é possível identificar importantes 
distinções. Além de iniciar com a diretiva de 
encapsulamento "public" ou default, os construtores não 
possuem um tipo de retorno e tampouco podem ser precedidos 
de quaisquer outros tipos de qualificadores. Desse modo, a 
sua sintaxe é muito mais simples que a sintaxe aplicada à 
implementação de um método. 
 
 Outra característica peculiar do construtor é que seu 
nome deve sempre ser idêntico ao nome da classe. Desse 
modo, dificilmente haverá dificuldades em distinguir os 
construtores dos métodos. Se o nome for idêntico ao da 
classe, então se trata de um construtor. Além disso, se o 
nome for precedido por um tipo ou por um qualificador 
 6 
qualquer (static, final ou abstract), então se trata de um 
método. 
 
 Há dois procedimentos básicos a serem compreendidos 
para se trabalhar com construtores. O primeiro diz respeito 
à substituição do construtor padrão por um construtor 
alternativo e o segundo faz a inclusão de um construtor 
alternativo sem que seja eliminado o construtor padrão. 
 
 O exemplo abaixo faz uso de um construtor alternativo, 
o qual substitui o construtor padrão. 
 
Primeiramente devemos criar a classe Pessoa: 
 
public class Pessoa{ 
 String nome = null; 
 int idade = 0; 
 String endereco = null; 
 
 public Pessoa (String n, int i, String e){ 
 nome = n; 
 idade = i; 
 endereco = e; 
 } 
} 
 
Agora vamos criar a classe TestePessoa que irá criar um 
objeto da classe Pessoa. 
 
public class TestePessoa { 
 
 public static void main(String[] args) { 
 String nome = "Joao"; 
 int idade = 30; 
 String endereco = "Av Paulista 900"; 
 
 Pessoa joao = new Pessoa(nome, idade, endereco); 
 
 System.out.println(joao.nome); 
 System.out.println(joao.idade); 
 System.out.println(joao.endereco); 
 } 
} 
 
OBS: Note que a classe Pessoa possui apenas o construtor 
alternativo, o qual possui três parâmetros. A classe 
TestePessoa cria um novo objeto da classe Pessoa (joao) 
utilizando este construtor alternativo. 
 
 A saída gerada pela execução da classe TestePessoa é a 
seguinte: 
 Joao 
 30 
 Av Paulista 900 
 
 7 
 Vamos analisar agora um segundo exemplo que faz a 
inclusão de um construtor alternativo sem que seja 
eliminado o construtor padrão. Neste caso a classe Pessoa 
irá possuir dois construtores. 
 
public class Pessoa{ 
 String nome = null; 
 int idade = 0; 
 String endereco = null; 
 
 public Pessoa(){ 
 
 } 
 
 public Pessoa (String n, int i, String e){ 
 nome = n; 
 idade = i; 
 endereco = e; 
 } 
} 
 
Agora vamos criar a classe TestePessoa que irá criar dois 
objetos da classe Pessoa. 
 
public class TestePessoa { 
 
 public static void main(String[] args) { 
 String nome = "Joao"; 
 int idade = 30; 
 String endereco = "Av Paulista 900"; 
 
 Pessoa joao = new Pessoa(nome, idade, endereco); 
 
 System.out.println(joao.nome); 
 System.out.println(joao.idade); 
 System.out.println(joao.endereco); 
 
 Pessoa maria = new Pessoa(); 
 
 System.out.println(maria.nome); 
 System.out.println(maria.idade); 
 System.out.println(maria.endereco); 
 } 
} 
 
OBS: Note que a classe Pessoa possui dois construtores: O 
primeiro é o padrão (default) e o segundo é o alternativo, 
o qual possui três parâmetros. A classe TestePessoa cria um 
novo objeto da classe Pessoa (joao) utilizando o construtor 
alternativo e em seguida cria um outro objeto da classe 
Pessoa (maria), porém desta vez utilizando o construtor 
padrão (default). 
 
 
 
 
 8 
 A saída gerada pela execução da classe TestePessoa é a 
seguinte: 
 
 Joao 
 30 
 Av Paulista 900 
 null 
 0 
 null 
 
 
Modificadores de Acesso de Visibilidade 
 
 Os modificadores de acesso visam controlar a 
acessibilidade dos elementos que compõem a classe. 
Conseqüentemente, podemos definir que apenas os métodos 
podem ser chamados, restringindo o acesso direto aos 
atributos. 
 
Modificador public 
 
 Quando utilizamos este modificador em atributos, 
métodos ou classes o compilador compreende que o atributo, 
método ou classe pode ser acessado diretamente por qualquer 
outra classe. 
 
 
Modificador private 
 
 Ao utilizarmos este modificador em atributos ou 
métodos implica que, para o compilador, estes elementos não 
podem ser acessados diretamente por qualquer outra classe, 
exceto por ela mesma. 
 
 O modificador private não é aplicável para classes. 
 
 
Modificador protected 
 
 As restrições impostas por esse tipo de modificador de 
acesso representam um nível intermediário entre o público e 
o privado. Com este modificador os atributos e métodos são 
acessíveis somente na própria classe, em classes 
especializadas e em classes do mesmo pacote. 
 
 O modificador protected não é aplicável para classes. 
 
 
 
 
 
 9 
Modificador default 
 
 O modificador default é utilizado quando não se 
especifica nenhum outro modificador, ou seja, quando não é 
especificado nenhum modificador, o atributo, método ou 
classe estão acessíveis apenas no mesmo pacote. 
 
 
Encapsulamento de atributos 
 
 Vamos imaginar que temos uma classe chamada Data com 
os seguintes atributos: ano, mes e dia. 
 
 Um usuário desatento poderia atribuir ao atributo ano 
um valor negativo, um mês igual a 20 ou um dia igual a 53. 
Todos este valores não são permitidos pois, um ano nunca 
poderia ser negativo, um mês nunca poderia ser maior do que 
12 e um dia nunca poderia ser maior do que 31. 
 
 Para uma implementação mais robusta destes atributos é 
interessante que o acesso seja mais controlado, ou seja, 
realizado através de métodos que permitam criar regras para 
atribuição e leitura. Esta prática é chamada 
encapsulamento. 
 
 Vantagens obtidas através da utilização do 
encapsulamento: 
 
• Validar valores a serem atribuídos a cada atributo; 
• Definir quais/quando os atributos podem ser 
alterados; 
• Fazer um log das modificações dos atributos; 
 
 
 O encapsulamento de atributos pode utilizar métodos 
padronizados. Contudo, quando existirem métodos 
relacionados à lógica de negócio, ou ainda, que facilitem a 
manipulação de atributos, podemos utilizar nomes que não 
sigam esta convenção. 
 
 Os métodos padrão para encapsulamento são chamados 
Getters e Setters. 
 
 
Getters 
 
 São métodos que permitem a leitura de atributos da 
classe, sendo uma boa prática cria-los para cada atributo 
que desejarmos encapsular. 
 10 
Exemplos: 
 
 String getNome() 
 long getCpf() 
 
 
Setters 
 
 São métodos para modificar os valores dos atributos 
visando protege-los da escrita ou modificação indevida. É 
possível estabelecer certas normas e controles dentro dos 
métodos Setters. 
 
Exemplos: 
 
 void SetNome(String nome) 
 void setCpf(long cpf) 
 
 
Métodos is 
 
 São métodos utilizados para leitura de atributos 
booleanos. 
 
Exemplos: 
 
 boolean isConnected() 
 boolean isMaiorDeIdade() 
 
 
 Vamos analisar o exemplo abaixo e a utilização do 
encapsulamentodos atributos. 
 
public class Data{ 
 private int ano; 
 private byte mes; 
 private byte dia; 
 
 public int getAno() { 
 return ano; 
 } 
 public void setAno(int a) { 
 if (a > 0){ 
 ano = a; 
 } 
 else 
 System.out.println("Ano invalido"); 
 } 
 public byte getDia() { 
 return dia; 
 } 
 public void setDia(byte d) { 
 if (d > 0 && d <= 31){ 
 dia = d; 
 } 
 11 
 else 
 System.out.println("Dia invalido"); 
 } 
 public byte getMes() { 
 return mes; 
 } 
 public void ajustarMes(byte m) { 
 if (m > 0 && m <= 12){ 
 mes = m; 
 } 
 else 
 System.out.println("Mes invalido"); 
 } 
 public boolean isAnoBissexto(){ 
 if (((ano % 4 == 0) && (ano % 100 != 0)) || (ano % 400 == 0)) 
 return true; 
 else 
 return false; 
 } 
} 
 
 
 Podemos observar pela classe acima que ao invés de 
modificar os atributos diretamente, devemos fazê-lo através 
dos métodos de acesso aos atributos. 
 
 Os métodos setAno, setDia e ajustarMes alteram os 
valores dos atributos ano, dia e mes respectivamente. Cada 
método faz validações antes de realizar a atribuição 
propriamente dita, isto impede que valores incorretos sejam 
atribuídos aos atributos. 
 
 O nome dos métodos não precisa começar necessariamente 
com a palavra "set", você pode implementar um método com 
qualquer outro nome. Como exemplo disto, foi criado o 
método "ajustarMes", porém o mesmo poderia se chamar 
"setMes" também. 
 
 
Modificadores de Acesso – Membros estáticos e 
finais 
 
Modificador static 
 
 Atributos: 
 Quando temos um atributo estático dentro de 
uma classe, este atributo será único para todos os objetos 
instanciados a partir desta classe. 
 
 Os atributos estáticos podem ser acessados 
diretamente a partir da classe e são alocados na memória na 
primeira vez que forem referenciados. Portanto, não é 
preciso criar uma instância (objeto) da classe. 
 12 
 Atributos estáticos devem ser utilizados 
quando for necessário compartilhar um valor entre todas as 
instâncias da classe. Desta forma, a variável será alocada 
apenas uma vez na memória. 
 
 Vejamos o exemplo da classe Pessoa (abaixo), 
que contém os seguintes atributos: 
 
 Nome: Característica específica de cada 
Pessoa, logo, é uma característica de cada instância; 
 Telefone: Cada Pessoa tem seu próprio 
telefone, que é uma característica da instância; 
 Sexo: Assinala-se o sexo de cada Pessoa com 
um int (1 ou 2) por exemplo. No intuito de padronizar é 
conveniente definir duas constantes: MASCULINO e FEMININO 
do tipo int. 
 
public class Pessoa{ 
 private String nome; 
 private String telefone; 
 int sexo; 
 public static int MASCULINO = 1; 
 public static int FEMININO = 2; 
 
 public void setSexo(int s){ 
 sexo = s; 
 } 
} 
 
Veja abaixo a classe TestePessoa: 
 
public class TestePessoa { 
 public static void main(String[] args) { 
 Pessoa joao = new Pessoa(); 
 
 joao.setSexo(Pessoa.MASCULINO); 
 } 
} 
 
 Foram criadas duas constantes para o sexo (MASCULINO e 
FEMININO) na classe Pessoa. Estas constantes são estáticas 
e, portanto podem ser utilizadas sem a necessidade de criar 
um objeto da classe. 
 
 Veja na classe TestePessoa que estamos acessando o 
atributo estático MASCULINO pela classe (Pessoa.MASCULINO) 
e não pela instância da classe. 
 
 Devemos tomar cuidado quando utilizamos atributos 
estáticos, pois eles são compartilhados por todas as 
instâncias da classe. 
 
 
 13 
Veja o exemplo abaixo: 
 
public class Carro { 
 public static String placa = "ABD-1563"; 
 
 public static void main(String[] args) { 
 Carro carro1 = new Carro(); 
 Carro carro2 = new Carro(); 
 
 System.out.println("Carro.placa: " + Carro.placa); 
 System.out.println("carro1.placa: " + carro1.placa); 
 System.out.println("carro2.placa: " + carro2.placa); 
 
 System.out.println("Alterando a placa do carro 1"); 
 carro1.placa = "DBX-4034"; 
 
 System.out.println("carro1.placa: " + carro1.placa); 
 System.out.println("carro2.placa: " + carro2.placa); 
 System.out.println("Carro.placa: " + Carro.placa); 
 } 
} 
 
 Veja abaixo a saída gerada pela execução do programa 
acima: 
 Carro.placa: ABD-1563 
 carro1.placa: ABD-1563 
 carro2.placa: ABD-1563 
 Alterando a placa do carro 1 
 carro1.placa: DBX-4034 
 carro2.placa: DBX-4034 
 Carro.placa: DBX-4034 
 
 O que aconteceu? 
 
 Perceba que a placa é a mesma para todos os objetos da 
classe Carro. Quando mudamos o valor da placa para qualquer 
uma das instâncias da classe Carro, todas as demais são 
afetadas porque o atributo placa é estático e compartilhado 
por todas as instâncias da classe. 
 
 
 Métodos: 
 Os métodos estáticos são aqueles que 
realizam tarefas que não dependem das características 
específicas de cada objeto. Para a execução da tarefa que 
se destinam, eles utilizam somente as informações contidas 
em seus próprios parâmetros e informações contidas em 
atributos estáticos. 
 
 A vantagem de um método estático em relação 
aos demais é que ele pode ser invocado a partir da própria 
classe, sem a necessidade de instanciá-la. 
 
 
 14 
 Como exemplo de métodos estáticos podemos 
citar os métodos parseXXX das classes Wrapper, pois estes 
métodos são utilizados sem a necessidade de criar uma 
instância da classe. 
 
 Veja o exemplo abaixo: 
 
public class Exemplo005 { 
 public static void main(String[] args) { 
 String str = "130"; 
 
 int num = Integer.parseInt(str); 
 } 
} 
 
 Note que o método parseInt da classe Integer foi 
invocado sem a necessidade da criação da instância da 
classe Integer. Portanto este é um método estático. 
 
 Um outro exemplo de método estático é o método main, 
pois o mesmo é chamado pela JVM sem a criação da instância 
da classe. 
 
 
 Classes: 
 O modificador static não é aplicável para 
classes. 
 
 
Modificador final 
 
 Atributos: 
 Quando o modificador final é utilizado em 
atributos, significa que somente uma atribuição poderá ser 
feita ao atributo, podendo ser feita na declaração ou no 
construtor. Em outras palavras, quando queremos declarar um 
atributo constante devemos utilizar o modificador final. 
 
 Veja o exemplo abaixo: 
 
public class TesteFinal { 
 private final int num = 350; 
 
 public static void main(String[] args) { 
 TesteFinal tf = new TesteFinal (); 
 
 tf.num = 100; 
 } 
} 
 
 
 
 
 15 
 Quando compilamos a classe TesteFinal obtemos o 
seguinte erro de compilação: 
 
 cannot assign a value to final variable num 
 
 Isto quer dizer que não podemos atribuir um novo valor 
(100) ao atributo final "num", pois o mesmo já tinha sido 
iniciado com o valor 350. 
 
 
 Métodos: 
 Podemos utilizar o modificador final na 
declaração de um método para que este não possa ser 
sobrescrito em classes filhas. 
 
OBS: Sobrescrita de métodos será visto mais adiante. 
 
 
 Classes: 
 O modificador final pode ser utilizado na 
declaração de classes, indicando que não poderá ser 
estendida por outra, ou seja, não poderá ser herdada. 
 
OBS: Herança será visto mais adiante. 
 
 
Relacionamento Entre Classes 
 
 
 Uma das formas mais simples de relacionamento entre 
classes é a associação, que ocorre quando temos uma classe 
que possui um atributo de outra classe (objetos ou array de 
objetos). 
 
Cardinalidade / Multiplicidade 
 
 Alguns valores que podem ser utilizados para definir a 
multiplicidade de um dos lados do relacionamento são: 
 
 1 Obrigatoriamente 1 
 0..1 Zero ou um 
 1..* Um ou mais 
 0..* Zero ou mais 
 * Zero ou mais 
 
 
OBS: Quando não definimos valores para acardinalidade fica 
implícito que o valor da associação é 1. 
 
 
 
 16 
Exemplo de associação 1 para 1 
 
 O exemplo abaixo pode ser lido da seguinte forma: Uma 
Pessoa tem um Endereço e o Endereço pertence a uma Pessoa. 
 
 
 
 
 
 
 
 Através do diagrama apresentado, podemos assumir que a 
classe Pessoa tem um atributo do tipo Endereço, e a classe 
Endereço tem um atributo do tipo Pessoa. 
 
 
Exemplo de associação 1 para muitos 
 
 Podemos assumir a partir do seguinte diagrama que uma 
Empresa pode ter um ou mais Departamentos, e cada 
Departamento pertence a apenas uma Empresa. 
 
 
 
 
 
 
 A partir do diagrama acima podemos assumir que na 
implementação, a classe Empresa deve ter uma coletividade 
de departamentos. 
 
 Veja o exemplo abaixo: 
 
Empresa.java 
public class Empresa{ 
 private Departamento[] departamentos; 
} 
 
 
Departamento.java 
public class Departamento{ 
 Private Empresa empresa; 
} 
 
 
Exemplo de associação muitos para muitos 
 
 O relacionamento muitos para muitos apresentado a 
seguir pode ser entendido da seguinte forma: Um funcionário 
trabalha para um ou mais departamentos, e um departamento 
emprega uma ou mais pessoas, ou seja, não temos um 
Funcionário que não trabalha para nenhum departamento, 
Pessoa Endereço 
tem 
Empresa Departamento 
tem 
1..* 
 17 
assim como não temos um departamento que não emprega nenhum 
funcionário. 
 
 
 
 
 
Funcionario.java 
public class Funcionario{ 
 private Departamento[] departamentos; 
} 
 
 
Departamento.java 
public class Departamento{ 
 Private Funcionario[] funcionarios; 
} 
 
 
Classe Calendar 
 
 A classe Calendar é uma classe abstrata que provê 
métodos para conversão entre um instante específico no 
tempo e um conjunto de atributos tais como ano (YEAR), mês 
(MONTH), dia (DAY), hora (HOUR) e assim por diante. 
 
 A classe Calendar possui um método chamado 
"getInstace", que é utilizado para gerar um objeto 
(instância) da classe. O método getInstance da classe 
Calendar retorna um objeto Calendar cujos atributos são 
iniciados com a data e hora atual. 
 
Exemplo: 
 Calendar agora = Calendar.getInstance(); 
 
OBS: Não é possível gerar um objeto da classe Calendar por 
meio do operador new. 
 
Obtendo e ajustando valores para os atributos da classe 
Calendar: 
 
public int get(int field) 
 
 O método get é utilizado para obter o valor presente 
(atual) do atributo passado como parâmetro. 
 
Exemplo: 
 c.get(Calendar.YEAR); // Este comando retorna o ano 
que está presente no atributo YEAR da classe calendar. 
 
 
Funcionário Departamento 
1..* 1..* 
 18 
public void set(int field, int value) 
 
 O método set é utilizado para alterar o valor presente 
(atual) do atributo passado como parâmetro para o valor 
passado como parâmetro. 
 
Exemplo: 
 c.set(Calendar.YEAR, 1990); // Este comando altera o 
valor do atributo ano (YEAR) para 1990. 
 
Veja o exemplo abaixo: 
 
import java.util.Calendar; 
public class TesteCalendar { 
 public static void main (String args[]){ 
 //obtem a instancia 
 Calendar c = Calendar.getInstance(); 
 
//métodos getters para obter: ano, mes, dia, hora, minuto e segundo 
 //retorna o ano 
 System.out.println(c.get(Calendar.YEAR)); 
 //retorna o mês. Janeiro é o primeiro mês, o qual possui índice zero 
 System.out.println(c.get(Calendar.MONTH)+1); 
 //retorna o dia do mês. O primeiro dia é 1. 
 System.out.println(c.get(Calendar.DAY_OF_MONTH)); 
 //retorna a hora em um ciclo de 12 horas. 
 //Exemplo: 10 horas (não se sabe se é manhã ou tarde) 
 System.out.println(c.get(Calendar.HOUR)); 
 //retorna a hora em um ciclo de 24 horas. 
 //Exemplo: 22:00 (dez horas da noite) 
 System.out.println(c.get(Calendar.HOUR_OF_DAY)); 
 //retorna minuto 
 System.out.println(c.get(Calendar.MINUTE)); 
 //retorna segundo 
 System.out.println(c.get(Calendar.SECOND)); 
 
//metodos setters para modificar: ano, mês, dia, hora minuto e segundo 
 //altera o ano para 1990 
 c.set(Calendar.YEAR, 1990); 
 //altera o mês para Dezembro 
 c.set(Calendar.MONTH, 11); 
 //altera o dia para 25 
 c.set(Calendar.DAY_OF_MONTH, 25); 
 //altera a hora para onze da noite 
 c.set(Calendar.HOUR_OF_DAY, 23); 
 //altera o minuto para zero 
 c.set(Calendar.MINUTE, 0); 
 //altera o segundo para zero 
 c.set(Calendar.SECOND, 0); 
 
 System.out.println(c.get(Calendar.YEAR)); 
 System.out.println(c.get(Calendar.MONTH)+1); 
 System.out.println(c.get(Calendar.DAY_OF_MONTH)); 
 System.out.println(c.get(Calendar.HOUR)); 
 System.out.println(c.get(Calendar.HOUR_OF_DAY)); 
 System.out.println(c.get(Calendar.MINUTE)); 
 System.out.println(c.get(Calendar.SECOND)); 
 } 
} 
 19 
Herança 
 
 
 Herança é o mecanismo que possibilita a definição de 
novas classes a partir de uma já existente, como forma de 
reutilizar seus atributos e métodos. Isso é possível mesmo 
quando não se tem acesso ao código fonte da superclasse. 
 
 A aplicação do mecanismo de herança sempre envolve 
dois elementos: uma superclasse e uma subclasse. A 
superclasse, também conhecida como classe ancestral, é 
aquela que representa as características genéricas de um 
conjunto de objetos. A subclasse, também conhecida como 
classe descendente, é aquela que estende a superclasse para 
incluir a representação de características específicas de 
um subconjunto desses objetos. 
 
 Vale destacar que as classes que contenham o 
qualificador final não podem ser estendidas. Isso significa 
que não se pode utilizá-las como superclasse em uma 
operação de especialização porque o qualificador final 
indica exatamente que elas não podem conter subclasses. 
 
 
A Declaração extends 
 
 O termo extends é utilizado na declaração de uma 
classe para especificar quem é sua superclasse. Caso ele 
seja omitido, como se fez em todos os exemplos anteriores, 
a classe Object será assumida como a superclasse da nova 
classe. Ou seja, quando a palavra chave extends for 
omitida, o compilador irá adicionar automaticamente a 
palavra extends e a classe java.lang.Object como 
superclasse da classe atual. A classe Object é chamada de 
superclasse de todas as classes, pois todas são derivadas 
dela. 
 
 A declaração extends figura depois do nome da nova 
classe. Observe a sintaxe: 
 
[public] [abstract | final] class <subclasse> extends <superclasse> 
 
 
Veja o exemplo abaixo: 
 
public class PessoaFisica extends ClienteBanco{ 
 
} 
 
 
 
 20 
 Note que a única novidade desta forma de declaração, 
comparativamente aquela adotada até aqui, é a presença do 
termo "extends" após o nome da classe (PessoaFisica) 
seguido do nome da superclasse, que neste caso, é a classe 
ClienteBanco. 
 
 Suponha que a classe anterior tenha sido declarada da 
seguinte forma: 
 
public class PessoaFisica{ 
 
} 
 
 Observe que a declaração extends foi omitida. Nesse 
caso, a classe PessoaFisica terá como superclasse a classe 
Object, uma vez que toda e qualquer classe implementada em 
Java é vinculada, explicitamente ou implicitamente, à 
hierarquia de classes de sua API. Como a classe Object é 
aquela que se encontra no topo dessa hierarquia, ela é 
assumida como a superclasse de todas as novas classes que 
não contenham a declaração extends para indicar, 
explicitamente, a sua superclasse. 
 
 Java não possui herança múltipla, ou seja, uma classe 
não pode herdar atributos e métodos diretamente de mais de 
uma classe 
 
A Referência this 
 
 Cada objeto que é instanciado a partir de uma classe 
Java mantém uma cópia própria dos atributos para que os 
valores neles armazenados não se confundam com os valores 
dos demais.No entanto, somente uma cópia de cada método é 
mantida para cada classe. Isso significa que, quando um 
objeto invoca um de seus métodos, ele está executando a 
única cópia desse método, que é compartilhada com todos os 
demais objetos dessa mesma classe. 
 
 A referência this é um valor especial através do qual 
é possível referir-se ao objeto corrente de uma classe 
dentro de quaisquer métodos da mesma. É através dessa 
referência que é possível identificar o objeto específico 
que invocou determinado método. 
 
 Quando uma classe possui algum atributo cujo nome 
coincide com o nome de um parâmetro de um método, a 
referência this torna-se especialmente importante. É 
somente através dela que é possível referir-se ao atributo 
da classe dentro do método que contém um parâmetro cujo 
nome coincida com o seu. 
 
 21 
 Para fazer referência a um atributo ou a um método do 
objeto corrente dentro de quaisquer métodos, basta utilizar 
a referência this seguida do operador ponto e do nome do 
atributo ou do método. Veja a sintaxe: 
 
 this.<atributo> 
 this.<método> 
 
 Suponha a classe Amigo, contendo um atributo chamado 
"nome" e um método chamado setNome(). Se o método setNome() 
possuir um parâmetro chamado "nome", a única forma de você 
se referir ao atributo "nome" dessa classe dentro desse 
método é utilizando a referência this, como segue: 
 
public class Amigo{ 
 private String nome; 
 
 public void setNome(String nome){ 
 this.nome = nome; 
 } 
} 
 
 A referência this também é útil em classes onde há 
mais que um construtor. Nesse caso, é interessante que um 
construtor faça uso da tarefa que já está sendo realizada 
por outro. Isso também é possível com o uso da referência 
this. 
 
Veja um exemplo: 
 
public class Amigo{ 
 private String nome; 
 private String fone; 
 
 public Amigo(){ 
 this(new String(""), new String("")); 
 } 
 
 public Amigo(String nome, String fone){ 
 this.nome = nome; 
 this.fone = fone; 
 } 
} 
 
 Neste caso, a referência this foi utilizada, dentro do 
construtor padrão, para invocar o segundo construtor, 
utilizando como argumentos dois textos vazios. Esses dois 
argumentos serão atribuídos, pelo segundo construtor, aos 
atributos nome e fone. 
 
 
 
 
 
 22 
A Referência super 
 
 Enquanto a referência this permite que o objeto 
corrente seja identificado e que seus atributos e métodos 
sejam referenciados em seus próprios métodos, a referência 
super possibilita que atributos e métodos da superclasse 
sejam referenciados pelos métodos da subclasse. 
 
 Para referir-se a um atributo ou a um método da 
superclasse em um método de uma subclasse, basta utilizar a 
referência super seguida do operador ponto e do nome do 
atributo ou do nome do método. Observe a sintaxe: 
 
 super.<atributo> 
 super.<método> 
 
 Caso queira referir-se a um construtor da superclasse, 
a sintaxe é diferente. Nesse caso, deve ser utilizada a 
referência super seguida de um par de parênteses. Veja como 
seria invocado o construtor da superclasse, que não 
contenha parâmetros. 
 
 super(); 
 
 É importante lembrar que a superclasse pode conter 
diversos construtores alternativos. Caso o construtor que 
deseja invocar contenha parâmetros, você deve informar um 
valor para cada um deles entre os parênteses. 
 
 
Exemplo de herança 
 
 Vamos observar o exemplo abaixo para entender melhor o 
conceito de herança. Este exemplo compõe-se de três 
classes: Fornecedor, FornecedorPessoa, FornecedorEmpresa. 
 
 Observe que há setas que partem das classes 
FornecedorPessoa e FornecedorEmpresa em direção à classe 
Fornecedor, indicando a direção da operação de 
especialização que está sendo realizada. Nessa operação, a 
classe Fornecedor é a superclasse e as outras duas classes 
são as subclasses. 
 
 
 23 
 
 
 
 
 
 A classe Fornecedor representa duas características 
comuns a todos os fornecedores (nome e fone), a classe 
FornecedorPessoa adiciona duas características específicas 
que somente aqueles fornecedores que são pessoas físicas 
possuem (RG e CPF) e a classe FornecedorEmpresa adiciona 
duas características específicas de fornecedores que são 
pessoas jurídicas (Inscrição Estadual e CNPJ). 
 
 Veja na próxima página a implementação da classe 
Fornecedor. 
 
 
 
 
 
 
 
 
 
 
 
 
 
- IE: String 
- CNPJ: String 
+ FornecedorEmpresa() 
+ FornecedorEmpresa(nome: String, 
fone: String, IE: String, CNPJ: String) 
+ setIE(IE: String) :void 
+ setCNPJ(CNPJ: String) :void 
+ getIE() :String 
+ getCNPJ() :String 
FornecedorEmpresa FornecedorPessoa 
- nome: String 
- fone: String 
+ Fornecedor() 
+ Fornecedor(nome: String, fone: String) 
+ setNome(nome: String) :void 
+ setFone(fone: String) :void 
+ getNome() :String 
+ getFone() :String 
+ main(args: String[]) :void 
Fornecedor 
- RG: String 
- CPF: String 
+ FornecedorPessoa() 
+ FornecedorPessoa(nome: String, fone: 
String, RG: String, CPF: String) 
+ setRG(RG: String) :void 
+ setCPF(CPF: String) :void 
+ getRG() :String 
+ getCPF() :String 
 24 
public class Fornecedor{ 
 private String nome; 
 private String fone; 
 
 public Fornecedor(){ 
 this ("", ""); 
 } 
 
 public Fornecedor(String nome, String fone){ 
 this.nome = nome; 
 this.fone = fone; 
 } 
 
 public void setNome(String nome){ 
 this.nome = nome; 
 } 
 
 public void setFone (String fone){ 
 this.fone = fone; 
 } 
 
 public String getNome(){ 
 return nome; 
 } 
 
 public String getFone(){ 
 return fone; 
 } 
 
 public static void main (String args[]){ 
 FornecedorPessoa carlos = new FornecedorPessoa(); 
 FornecedorEmpresa gtaLtda = new FornecedorEmpresa(); 
 
 carlos.setNome("Carlos"); 
 carlos.setFone("2345-6789"); 
 carlos.setRG("26.832.821-5"); 
 carlos.setCPF("237.235.385-32"); 
 
 gtaLtda.setNome("Gta transportes LTDA"); 
 gtaLtda.setFone("2543-3675"); 
 gtaLtda.setIE("23.2582.214"); 
 gtaLtda.setCNPJ("36.254.321/0001-52"); 
 
 System.out.println("Nome da Pessoa: " + carlos.getNome()); 
 System.out.println("Nome da Empresa: " + gtaLtda.getNome()); 
 
 } 
} 
 
 Observe no método main acima que o objeto "carlos" e o 
objeto "gtaLtda" são do tipo FornecedorPessoa e 
FornecedorEmpresa respectivamente e que ambos estão 
utilizando os métodos setNome(), setFone() e getNome(), 
porém as classes FornecedorPessoa e FornecedorEmpresa não 
possuem estes métodos. 
 
 Devemos lembrar que os métodos citados acima são 
herdados da superclasse (Fornecedor), e devido a isto os 
objetos têm acesso a estes métodos. 
 25 
 
 Abaixo a implementação da classe FornecedorPessoa. 
 
 
public class FornecedorPessoa extends Fornecedor{ 
 private String RG; 
 private String CPF; 
 
 public FornecedorPessoa(){ 
 this("", "", "", ""); 
 } 
 
 public FornecedorPessoa(String nome, String fone, 
 String RG, String CPF){ 
 super(nome, fone); 
 this.RG = RG; 
 this.CPF = CPF; 
 } 
 
 public void setRG(String RG){ 
 this.RG = RG; 
 } 
 
 public void setCPF (String CPF){ 
 this.CPF = CPF; 
 } 
 
 public String getRG(){ 
 return RG; 
 } 
 
 public String getCPF(){ 
 return CPF; 
 } 
} 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 26 
 Abaixo a implementação da classe FornecedorEmpresa. 
 
public class FornecedorEmpresa extends Fornecedor{ 
 private String IE; 
 private String CNPJ; 
 
 public FornecedorEmpresa(){ 
 this("", "", "", ""); 
 } 
 
 public FornecedorEmpresa(String nome, String fone, 
 String IE, String CNPJ){ 
 super(nome, fone); 
 this.IE = IE; 
 this.CNPJ = CNPJ; 
 }public void setIE(String IE){ 
 this.IE = IE; 
 } 
 
 public void setCNPJ (String CNPJ){ 
 this.CNPJ = CNPJ; 
 } 
 
 public String getIE(){ 
 return IE; 
 } 
 
 public String getCNPJ(){ 
 return CNPJ; 
 } 
} 
 
 
Sobrescrita e Sobrecarga de métodos e construtores 
 
 
Sobrecarga 
 
 A sobrecarga (overload em inglês) é a implementação, 
em uma mesma classe ou em classes ligadas pelo mecanismo de 
herança, de duas ou mais versões para um mesmo método, de 
modo que manifestem comportamentos distintos. Nesse caso, o 
que os distinguirá é sua assinatura, ou seja, seu conjunto 
de parâmetros. 
 
 Sobrecarregar um método é escrever métodos com nomes 
iguais, porém, com quantidade e tipos de parâmetros de 
entrada diferentes. Não é possível implementar um método 
duas vezes com os mesmos tipos e quantidades de parâmetros. 
 
 Também é possível realizar a sobrecarga de 
construtores. Para isto basta definir mais do que um 
construtor seguindo as mesmas regras da sobrecarga de 
métodos. 
 27 
 
Veja abaixo um exemplo da sobrecarga de métodos. 
 
public class Calculadora{ 
 
 public int soma (int a, int b){ 
 return a + b; 
 } 
 
 public int soma (int a, int b, int c){ 
 int resultado = this.soma(a, b) + c; 
 return resultado; 
 } 
 
 public float soma (float a, float b){ 
 return a + b; 
 } 
 
 public long soma (int[] numeros){ 
 long resultado = 0; 
 
 for (int cont = 0; cont < numeros.length; cont++){ 
 retultado += numeros[cont]; 
 } 
 
 return resultado; 
 } 
} 
 
 No exemplo acima foi feita a sobrecarga do método 
soma. Note que existem quatros implementações diferentes 
para o método soma e que a assinatura é diferente para cada 
método. 
 
Veja abaixo um exemplo da sobrecarga de construtores 
 
public class Pessoa{ 
 private String nome; 
 private String fone; 
 
 public Pessoa(){ 
 this ("", ""); 
 } 
 
 public Pessoa(String nome, String fone){ 
 this.nome = nome; 
 this.fone = fone; 
 } 
} 
 
 
Sobrescrita 
 
 A sobrescrita (override em inglês) é a implementação 
de métodos em subclasses que possuem o mesmo nome e mesma 
assinatura de métodos de sua superclasse, de tal forma que 
 28 
anule o comportamento que ele apresentava em sua 
superclasse ou apenas acrescente novas instruções. 
 
 As seguintes regras devem ser respeitadas ao 
sobrescrever um método de uma superclasse: 
 
� O novo método deve ter exatamente o mesmo nome 
daquele que queremos sobrescrever; 
� O método deverá ter a mesma lista de parâmetros 
(assinatura); 
� O retorno do método deverá ser o mesmo do 
método que estamos sobrescrevendo; 
� Não podemos lançar Exceptions que não estejam 
declaradas no método, ou seja, apenas a mesma 
Exception declarada na assinatura do método ou 
que sejam subclasses daquela declarada; 
� Um método static não pode sobrescrever um 
método não static e vice-versa; 
� Um método não dever ter um modificador de 
acesso mais restritivo que o método 
sobrescrito; 
 
Veja abaixo um exemplo da sobrescrita de métodos. 
 
SuperClasse.Java 
 
public class SuperClasse{ 
 
 public void metodoImprimir(){ 
 System.out.println("SuperClasse - metodoImprimir"); 
 } 
} 
 
 
ClasseFilha.Java 
 
public class ClasseFilha extends SuperClasse{ 
 
 public void metodoImprimir(){ 
 System.out.println("ClasseFilha -sobrescrita do metodoImprimir"); 
 } 
} 
 
 O método "metodoImprimir" da classe "ClasseFilha" está 
sobrescrevendo o método de mesmo nome da classe 
"SuperClasse". 
 
 
 
 
 29 
Sobrescrita do método toString() 
 
 A classe Object, como já descrito anteriormente, é a 
classe pai de todas as classes da hierarquia de classes 
Java. 
 
 Esta classe possui um método chamado toString(), que 
tem como objetivo retornar uma representação em String do 
objeto em questão. Segundo o javadoc, é recomendado que 
todas as subclasses sobrescrevam este método. 
 
 Caso este método não seja sobrescrito e seja invocado 
pelo objeto, a seguinte string será retornada: 
 
 <nomeDaClasse>@hashCode 
 
Vejamos o exemplo abaixo: 
 
public class Pessoa{ 
 private String nome; 
 private int idade; 
 private String endereco; 
 private String tel; 
 
 public Pessoa (String nome, int idade, 
 String endereco, String tel){ 
 this.nome = nome; 
 this.idade = idade; 
 this.endereco = endereco; 
 this.tel = tel; 
 } 
 
 public String toString(){ 
 String str = this.nome + "\n" + 
 idade + "\n" + 
 this.endereco + "\n" + 
 tel; 
 return str; 
 } 
 
 public static void main (String args[]){ 
 Pessoa p = new Pessoa("Leandro", 25, 
 "Rua XV", "2586-3247"); 
 
 String str = p.toString(); 
 
 System.out.println(str + "\n"); 
 System.out.println(p); 
 } 
} 
 
 Note na classe Pessoa (acima) que a mesma sobrescreve 
o método toString() da classe Object . O novo método faz 
uma concatenação de todos os atributos da classe e retorna 
a string desta concatenação. 
 
 30 
 Observe no método main que existem duas formas de 
invocar o método toString(): A primeira é chamando 
explicitamente o método e a segunda é chamando o método 
println passando como parâmetro o próprio objeto. 
 
 
 Veja abaixo a saída gerada pela execução da classe 
Pessoa: 
Leandro 
25 
Rua XV 
2586-3247 
 
Leandro 
25 
Rua XV 
2586-3247 
 
 Caso a classe Pessoa não sobrescrevesse o método 
toString(), a saída gerada pela execução da classe seria a 
seguinte: 
Pessoa@10b62c9 
 
Pessoa@10b62c9 
 
 
Polimorfismo 
 
 Polimorfismo é uma palavra de origem grega que 
significa muitas formas. 
 
 Polimorfismo é um mecanismo da POO que possibilita a 
sobrecarga de métodos e construtores dentro de uma mesma 
classe ou sobrecarga de métodos em subclasses e a 
sobrescrita de métodos em subclasses. 
 
 O polimorfismo ocorre quando um mesmo trecho de código 
assume comportamentos diferenciados de acordo com o estado 
do objeto. Em outras palavras, quando subtipos herdam um 
comportamento de um supertipo, porém o executam de forma 
diferenciada. 
 
 
 
 
 
 
 
 
 
 
 31 
 Veja o exemplo abaixo: 
 
Bicho.java 
public class Bicho{ 
 
 public void fala(){ 
 } 
} 
 
Cachorro.java 
 
public class Cachorro extends Bicho{ 
 
 public void fala(){ 
 System.out.println("Au au"); 
 } 
} 
 
 
Gato.java 
 
public class Gato extends Bicho{ 
 
 public void fala(){ 
 System.out.println("Miau"); 
 } 
} 
 
 
TestePolimorfismo.java 
 
public class TestePolimorfismo{ 
 
 public static void main(String args[]){ 
 Bicho b; 
 
 if (args[0].equals("cachorro")){ 
 b = new Cachorro(); 
 } 
 else{ 
 b = new Gato(); 
 } 
 
 b.fala(); 
 } 
} 
 
 
 O polimorfismo está no método fala. Note que a classe 
Bicho é a generalização das classes Cachorro e Gato, logo 
todo cachorro é um Bicho e todo Gato também é um Bicho. 
 
 Com isto é possível armazenar a instância do objeto 
Cachorro ou Gato em uma variável do tipo Bicho e com isto 
podemos realizar o polimorfismo através do método fala. 
 32 
 
 Vamos ver agora mais um exemplo para desenvolver o 
entendimento acerca do mecanismo de polimorfismo. Vamos 
analisar o diagrama de classes abaixo. 
 
 A classe Veículo será a superclasse das outras duas 
classes (Ônibus e caminhão) e será utilizada para 
demonstrar tanto a sobrecarga de construtores quanto a 
sobrecarga de métodos. As classes Ônibus e Caminhão, por 
sua vez, ilustrarão a sobrescrita de métodos. 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
- pesoCarga: int 
+ Caminhao(placa: String, ano:int, 
pesoCarga: int) 
+ setPesoCarga(pesoCarga: int) :void 
+ getPesoCarga() :int 
+ mostrarDados() :void 
Caminhao Onibus 
- placa: String 
- ano: int 
+ Veiculo() 
+ Veiculo(placa: String, ano: int) 
+ setPlaca(placa: String) :void 
+ setAno(ano: int) :void 
+ setAno(ano: String) :void 
+ getPlaca() :String 
+ getAno() :int 
+ mostrarDados() : void 
+ main(args: String[]) :void 
Veiculo 
- passageiros: int 
+ Onibus(placa: String, ano: int, 
passagerios: int) 
+ setPassageiros(passageiros: int) :void 
+ getPassageiros() :int 
+ mostrarDados() :void 
 33 
 
Veja abaixo a classe Veículo. 
 
public class Veiculo{ 
 private String placa; 
 private int ano; 
 
 public Veiculo(){ 
 this("", 0); 
 } 
 
 public Veiculo(String placa, int ano){ 
 this.placa = placa; 
 this.ano = ano; 
 } 
 
 public void setPlaca(String placa){ 
 this.placa = placa; 
 } 
 
 public void setAno(int ano){ 
 this.ano = ano; 
 } 
 
 public void setAno(String ano){ 
 this.ano = Integer.parseInt(ano); 
 } 
 
 public String getPlaca(){ 
 return placa; 
 } 
 
 public int getAno(){ 
 return ano; 
 } 
 
 public void mostrarDados(){ 
 System.out.println("\n------Dados do veiculo--------"); 
 System.out.println("placa: " + this.getPlaca()); 
 System.out.println("ano: " + this.getAno()); 
 } 
 
 public static void main (String args[]){ 
 Veiculo veiculo = new Veiculo(); 
 Onibus onibus = new Onibus("DXG-3592", 1982, 40); 
 Caminhao caminhao = new Caminhao("BWE-2712", 1990, 1208); 
 
 veiculo.setPlaca("BDE-6419"); 
 veiculo.setAno(1995); 
 
 onibus.setPlaca("CTD-6582"); 
 
 caminhao.setAno("2003"); 
 
 veiculo.mostrarDados(); 
 onibus.mostrarDados(); 
 caminhao.mostrarDados(); 
 } 
} 
 34 
 A classe veículo compõe-se de dois atributos privados, 
dois construtores e sete métodos, incluindo o método 
main(). A presença de duas versões distintas do construtor 
caracteriza o primeiro caso de sobrecarga dessa classe, e a 
presença de duas versões distintas do método setAno() 
caracteriza o segundo caso. 
 
 A declaração extends não está presente na 
implementação da classe Veículo, o que significa que ela, 
implicitamente, deriva diretamente da classe Object. Seus 
atributos, placa e ano, representam duas características 
comuns dos objetos do mundo real que essa classe 
representa: os veículos em geral. 
 
 A presença de duas versões distintas para o construtor 
da classe Veículo só é possível porque a linguagem Java dá 
suporte ao polimorfismo. Caso ele não fosse suportado, 
seria necessário excluir uma das versões do construtor e 
manter apenas uma. 
 
 Note também a sobrecarga do método setAno() que possui 
duas assinaturas, uma com parâmetro do tipo int e outra do 
tipo String. 
 
 O método mostrarDados() da classe veículos apresenta 
na tela as informações contidas nos atributos placa e ano. 
Este método é importante, dentro do contexto deste exemplo, 
pois o mesmo também será implementado nas classes Ônibus e 
Caminhão e com isto será possível exemplificar a 
sobrescrita de métodos. 
 
Veja abaixo a classe Ônibus. 
public class Onibus extends Veiculo{ 
 private int passageiros; 
 
 public Onibus(String placa, int ano, int passageiros){ 
 super (placa, ano); 
 this.passageiros = passageiros; 
 } 
 
 public void setPassageiros(int passageiros){ 
 this.passageiros = passageiros; 
 } 
 
 public int getPassageiros(){ 
 return passageiros; 
 } 
 
 public void mostrarDados(){ 
 System.out.println("\n-----Dados do Onibus--------"); 
 System.out.println("Qtde passageiros:"+ this.getPassageiros()); 
 System.out.println("Placa onibus: " + getPlaca()); 
 System.out.println("Ano onibus: " + super.getAno()); 
 } 
} 
 35 
 Note na classe Ônibus que a mesma estende a classe 
Veículo, e com isto herda todos os atributos e métodos da 
mesma. Além disto, a classe Ônibus declara um atributo que 
é específico dos Ônibus: o atributo "passageiros", que 
representa a quantidade de passageiros presentes no Ônibus. 
 
 A classe Ônibus declara um único construtor que recebe 
como parâmetro a placa, o ano e passageiros para o Ônibus. 
Para iniciar os atributos placa e ano, é feita a chamada do 
construtor de sua superclasse, ou seja, a classe Veículo. 
 
 A classe Ônibus realiza a sobrescrita do método 
mostrarDados() de sua superclasse, ou seja, o método da 
classe Ônibus realizar uma tarefa diferente daquele 
implementado na superclasse. 
 
 
Veja abaixo a classe Caminhão. 
 
public class Caminhao extends Veiculo{ 
 private int pesoCarga; 
 
 public Caminhao(String placa, int ano, int pesoCarga){ 
 super (placa, ano); 
 this.pesoCarga = pesoCarga; 
 } 
 
 public void setPesoCarga(int pesoCarga){ 
 this.pesoCarga = pesoCarga; 
 } 
 
 public int getPesoCarga(){ 
 return pesoCarga; 
 } 
 
 public void mostrarDados(){ 
 super.mostrarDados(); 
 System.out.println("Peso da carga: " + getPesoCarga()); 
 } 
} 
 
 Note na classe Caminhão que a mesma estende a classe 
Veículo, e com isto herda todos os atributos e métodos da 
mesma. Além disto, a classe Caminhão declara um atributo 
que é específico dos Caminhões: o atributo "pesoCarga", que 
representa a o peso da carga do caminhão. 
 
 A classe Caminhão declara um único construtor que 
recebe como parâmetro a placa, o ano e pesoCarga para o 
Caminhão. Para iniciar os atributos placa e ano, é feita a 
chamada do construtor de sua superclasse, ou seja, a classe 
Veículo. 
 
 36 
 A classe Caminhão realiza a sobrescrita do método 
mostrarDados() de sua superclasse, porém ao contrário da 
classe Ônibus que faz uma implementação diferente do método 
mortarDados() da superclasse, o método mostrarDados() da 
classe Caminhão realiza uma tarefa complementar ao método 
da superclasse, pois dentro deste método é feita a chamada 
ao seu correspondente na superclasse e em seguida realiza a 
sua tarefa específica. 
 
 Após a compilação destas classes e execução da classe 
Veículo, veja abaixo a saída gerada. 
 
------Dados do veiculo-------- 
placa: BDE-6419 
ano: 1995 
 
-----Dados do Onibus-------- 
Qtde passageiros:40 
Placa onibus: CTD-6582 
Ano onibus: 1982 
 
------Dados do veiculo-------- 
placa: BWE-2712 
ano: 2003 
Peso da carga: 1208 
 
 
Conversão de Tipos (Type Casting) 
 
 A operação de cast de objetos é semelhante à operação 
de cast de tipos primitivos, com a diferença que, no 
segundo o tipo e a estrutura da variável são alterados 
definitivamente e, no primeiro, as características e 
funcionalidades estarão apenas ocultas, podendo ser 
restituídos posteriormente. 
 
 Veja a estrutura hierárquica das classes abaixo: 
 
 
 
Object 
Pessoa 
Cliente Funcionário 
 37 
 É possível fazer cast de classes desde que estejam em 
uma mesma hierarquia; não podemos fazer cast entre classes 
"irmãs", tal como entre Funcionário e Cliente. 
 
 É importante ressaltar que o cast não representa uma 
mudança estrutural do objeto, mas tão somente o tipo de 
variável reference que está apontando para o objeto na 
memória. 
 
Cast up 
 
 Com base na hierarquia de classes do diagrama 
anterior, podemos concluir que: 
 
 Cliente é uma Pessoa e toda Pessoa é um Object. 
 
 
 Portanto, podemos realizar a operação de cast up, 
visualizando um objeto da classe Cliente como Pessoa ou 
Object, mas o objeto não perderá definitivamente suas 
características de Cliente. 
 
 Veja o exemplo abaixo: 
 
public class TesteCastUp{ 
 public static void main (String args[]){ 
 
 //O objeto c foi declarado e instanciado como Cliente 
 Cliente c = new Cliente(); 
 
 //Cast up explicito do objeto da classe Cliente para a classe Pessoa 
 Pessoa p = (Pessoa)c; 
 
 //Cast up do objeto da classe Cliente para a classe Pessoa 
 Pessoa p2 = c; 
 
 //Cast up do objeto da classe Cliente para Pessoa 
 Pessoa p3 = new Cliente(); 
 
 //Cast up explicito do objeto da classe Cliente para a classe Object 
 Object o = (Object) c; 
 
 //Cast up do objeto da classe Cliente para a classe Object 
 Object o2 = c; 
 } 
} 
 
 
 
 
 
 
 
 
 
 38 
Cast down 
 
 A operação de cast down é oposta à operação de cast 
up, isto é, ao invés de generalizarmos um objeto vamos 
especializá-lo. 
 
 A generalização é uma operação mais previsível do que 
especialização, porque a análise da hierarquia de classes 
permite saber se a operação é ou não possível, na 
especialização, ao contrário, a operação irá depender da 
forma como o objeto foi criado. 
 
 Por exemplo, se um objeto é criado e declarado como 
Cliente, e sofre um cast up para Pessoa, é possível fazer o 
cast down para voltar a visualizá-lo como Cliente, uma vez 
que foi criado como Cliente. No entanto, se um objeto é 
criado e declarado como Pessoa, não é possível fazer o cast 
down para transformá-lo em Cliente. 
 
 Lembrando que: Todo Cliente é uma Pessoa, mas nem toda 
Pessoa é um Cliente, assim a operação de cast down deverá 
ser feita sempre de forma explícita. 
 
 Veja o exemplo abaixo: 
 
public class TesteCastDown { 
 
 public static void main (String args[]){ 
 Cliente c = new Cliente(); 
 
 //Cast up de Cliente para Pessoa 
 Pessoa p = c; 
 
 //Cast down de Pessoa para Cliente 
 Cliente c2 = (Cliente) p; 
 
 //Criacao de uma instancia da classe Pessoa 
 Pessoa p2 = new Pessoa(); 
 
 //Cast down invalido de Pessoa para Cliente 
 Cliente c3 = (Cliente) p2; 
 } 
} 
 
 
 O Cliente é uma especialização da Pessoa, logo sempre 
é possível fazer um cast (up) de Cliente para Pessoa, porém 
só é possível fazer cast (down) de Pessoa para Cliente se o 
objeto armazenado em uma variável do tipo Pessoa for um 
Cliente. 
 
 No exemplo acima foi criado um Objeto a partir da 
classe Pessoa (p2) e em seguida tentou-se fazer um cast 
down para Cliente e isto irá gerar uma exceção em tempo de 
 39 
execução. Esta exceção chama-se "ClassCastException", ou 
seja, houve a tentativa de converter um objeto gerado a 
partir da classe Pessoa para um objeto da classe Cliente. 
 
 
 Veja abaixo a saída gerada pela execução do programa 
acima. 
 
Exception in thread "main" java.lang.ClassCastException: Pessoa 
 at TesteCastDown.main(TesteCastDown.java:16) 
 
 
Exemplo sobre conversão de tipos 
 
 Vamos analisar o exemplo abaixo para entender melhor a 
conversão de tipos para objetos. 
 
 Quando analisar as classes tenha em mente o diagrama 
de classes que está no início do tópico "Conversão de Tipos 
(Type Casting)". 
 
Pessoa.java 
 
public class Pessoa { 
 public void imprimir(){ 
 System.out.println("Dentro da classe Pessoa"); 
 } 
} 
 
 
Cliente.java 
 
public class Cliente extends Pessoa { 
 public void imprimir(){ 
 System.out.println("Dentro da classe cliente"); 
 } 
} 
 
 
Funcionario.java 
 
public class Funcionario extends Pessoa { 
 public void imprimir(){ 
 System.out.println("Dentro da classe funcionario"); 
 } 
} 
 
 
 
 
 
 
 
 40 
Teste.java 
 
public class Teste { 
 public static void main (String args[]){ 
 Cliente c = new Cliente(); 
 Funcionario f = new Funcionario(); 
 Teste t = new Teste(); 
 
 t.converter(c); 
 t.converter(f); 
 } 
 
 public void converter(Pessoa p){ 
 //verifica se o objeto p eh uma instancia da classe Cliente 
 if (p instanceof Cliente){ 
 Cliente cli = (Cliente) p; 
 cli.imprimir(); 
 } 
 else{ 
 Funcionario fun = (Funcionario) p; 
 fun.imprimir(); 
 } 
 } 
} 
 
 
 Neste exemplo a classe Pessoa é a superclasse das 
classes Cliente e Funcionário. 
 
 A classe Teste foi criada somente para dar suporte ao 
exemplo de polimorfismo e type casting. 
 
 Note que a classe Pessoa possui o método imprimir, o 
qual exibe na tela uma mensagem dizendo que está dentro da 
classe Pessoa. 
 
 As classes Cliente e Funcionário estendem a classe 
Pessoa (herança), sobrescrevem o método imprimir e cada uma 
imprima a sua mensagem na tela. 
 
 A classe Teste possui o método main e o método 
converter. No método main é criado um objeto da classe 
Cliente e outro da classe Funcionário. 
 
 Em seguida o método converter é chamado duas vezes: Na 
primeira passando como parâmetro um objeto da classe 
Cliente e na segunda passando um objeto da classe 
Funcionário. 
 
 Este procedimento só é possível porque Java suporta a 
orientação a objetos, uma vez que na assinatura do método 
converter podemos definir como parâmetro um objeto da 
classe Pessoa que é superclasse das classes Cliente e 
Funcionário. 
 41 
 Com isto, na chamada do método converter é feito um 
cast up de Cliente para Pessoa e em seguida de Funcinário 
para Pessoa. 
 
 Já dentro do método converter verifica-se se o 
parâmetro é uma instância da classe Cliente, e em caso 
afirmativo, faz-se um cast down de Pessoa para Cliente e em 
seguida chama-se o método imprimir. 
 
 Caso o parâmetro não seja uma instância da classe 
Cliente, significa que o mesmo é uma instância da classe 
Funcionário, e com isto é feito um cast down de Pessoa para 
funcionário e logo após chama-se o método imprimir. 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 42 
Exercícios Sobre Java e o Paradigma Orientado a 
Objeto 
 
1) Qual a diferença entre classe e objeto? 
 
2) Qual é a finalidade do método construtor? 
 
3) Identifique na instrução abaixo: a classe, o objeto, o 
construtor e a operação de instanciação. 
Computador computador = new Computador(); 
 
4) O que diferencia um construtor de um método qualquer? 
 
5) Observe que a classe abaixo não possui um construtor, 
porém para que seja criado um objeto sempre é 
necessário utilizar o operador new seguido do nome do 
construtor. Desta forma, não será possível criar um 
objeto desta classe? Explique. 
 
public class Garrafa{ 
 private String tipo; 
 
 public void setTipo (String tipo){ 
 this.tipo = tipo; 
 } 
 
 public String getTipo(){ 
 return tipo; 
 } 
} 
 
 
6) A classe abaixo é parecida com a classe do exercício 
anterior, porém agora ela possui um construtor 
alternativo. O que irá acontecer se em outra classe 
você desejar criar um objeto da mesma com a seguinte 
instrução: 
Garrafa gar = new Garrafa(); 
 
public class Garrafa{ 
 private String tipo; 
 
 public Garrafa (String tipo){ 
 this.tipo = tipo; 
 } 
 
 public void setTipo (String tipo){ 
 this.tipo = tipo; 
 } 
 
 public String getTipo(){ 
 return tipo; 
 } 
} 
 43 
 
7) As duas classes abaixo não estão no mesmo pacote. Faça 
uma análise das mesmas e corrija possíveis erros de 
compilação. 
 
public class Carro{ 
 protected int litrosNoTanque; 
 protected boolean carroLigado; 
 
 private void encherTanque(int litros){ 
 litrosNoTanque = litros; 
 } 
} 
 
public class TesteCarro{ 
 public static void main (String args[]){ 
 Carro carro = new Carro(); 
 
 carro.encherTanque(10); 
 carro.carroLigado = true; 
 } 
} 
 
 
8) Observe as classes Circulo e TesteCirculo abaixo e 
realize as seguintes tarefas: 
- Declare o atributo raio da classe Circulo como 
privado; 
- Crie os métodos necessários na classe Circulo de 
modo que seja possível obter ou alterar o valor do 
atributo raio pela classe TesteCirculo; 
- Caso o objetivo seja alterar o valor do atributoraio, faça a seguinte verificação: Se o valor do 
novo raio for positivo, faça a atribuição, caso 
contrário não faça; 
- Siga as orientações presentes na classe 
TesteCirculo e execute cada tarefa; 
 
public class Circulo{ 
 double raio; 
} 
 
 
public class TesteCirculo{ 
 public static void main (String args[]){ 
 /* Crie um objeto da classe Circulo */ 
 /* Coloque aqui o codigo para alterar o raio para 10 */ 
 /* Coloque aqui o codigo para obter o valor do raio */ 
 } 
} 
 
 
 44 
 
9) Observe as classes AcessaBanco e TesteBanco abaixo e 
realize as seguintes tarefas: 
- Declare os atributos login e conectado da classe 
AcessaBanco como privado; 
- Crie os métodos necessários na classe AcessaBanco 
de modo que seja possível obter ou alterar o valor 
dos atributos login e conectado pela classe 
TesteBanco; 
- Siga as orientações presentes na classe TesteBanco 
e execute cada tarefa; 
 
public class AcessaBanco{ 
 String login; 
 boolean conectado; 
} 
 
 
public class TesteBanco{ 
 public static void main (String args[]){ 
 /* Crie um objeto da classe AcessaBanco */ 
 /* Coloque aqui o codigo para alterar o login para o seu nome */ 
 /* Coloque aqui o codigo para ajustar conectado para true */ 
 } 
} 
 
 
10) Analise o código abaixo e descreva em poucas linhas 
onde está o erro de compilação e qual seria a solução 
para corrigir o mesmo. 
 
public class TesteStatic{ 
 private int a1; 
 private int a2; 
 
 public static void main (String args[]){ 
 iniciar(10,40); 
 } 
 
 public void iniciar(int v1, int v2){ 
 int b1 = v1; 
 int b2 = v2; 
 } 
} 
 
 
 
 
 
 
 
 45 
11) Analise as classes abaixo e descreva em poucas linhas 
se existe erro de compilação ou não. E caso exista 
algum, descreva qual deveria ser a solução. 
 
public final class Veiculo{ 
 private String chassi; 
 
 public String getChassi(){ 
 return chassi; 
 } 
} 
 
 
public class Carro extends Veiculo{ 
 private String cad; 
 
 public String getCad(){ 
 return cad; 
 } 
} 
 
 
12) A classe Jogo abaixo foi descrita sem atributos e 
métodos. 
public class Jogo{ } 
 
Logo após o processo de compilação foi utilizado o 
utilitário javap (que transforma código binário em 
código Java) e o mesmo retornou o código abaixo. 
 
public class Jogo extends java.lang.Object{ 
 public Jogo(); 
} 
 
Note que existem mais informações no código gerado 
pelo utilitário javap do que o código original. 
O que aconteceu? 
 
 
13) Analisando a classe Java abaixo podemos observar que a 
mesma possui apenas um atributo, um construtor e dois 
métodos. 
Perceba que dentro do método main estão sendo 
invocados métodos e atributos que não pertencem à 
classe. Isto é um erro de compilação? Justifique 
sua resposta. 
 
public class PessoaFisica extends Pessoa{ 
 private String RG; 
 
 public PessoaFisica(){ 
 super(); 
 } 
 public String getRG(){ 
 46 
 return RG; 
 } 
 
 public static void main (String args[]){ 
 PessoaFisica pf = new PessoaFisica(); 
 
 pf.setEndereco("Rua XV n. 10"); 
 pf.setFone("2546-3274"); 
 
 System.out.println(pf.endereco); 
 System.out.println(pf.fone); 
 } 
} 
 
 
14) Faça um programa em Java para implementar uma 
calculadora simples com as quatro operações básicas da 
matemática. Crie três métodos para cada uma das 
operações e cada método deverá ser sobrecarregado, pois 
um deles deve receber apenas dois parâmetros do tipo 
int, o outro apenas dois parâmetros do tipo float e o 
último apenas dois parâmetros do tipo String. Quando os 
parâmetros forem do tipo String, os mesmos deverão ser 
convertidos para o tipo int. 
 
 
15) Crie uma classe Java chamada ClienteBanco com os 
seguintes atributos (privados): 
- nome; 
- Data de Nascimento; 
- CPF; 
- endereço; 
Além do construtor padrão, crie um construtor 
alternativo para iniciar cada um dos atributos. 
Crie os métodos necessários para acessar estes 
atributos. 
Faça a sobrescrita do método toString() da classe 
Object para o mesmo retornar a seguinte mensagem: 
 "O Sr." <nome> "portador do CPF 
n." <CPF> "nascido em" <data de 
nascimento> "residente e domiciliado a 
" <endereço> "vem por meio desta 
solicitar o encerramento de sua conta 
corrente". 
 
Crie um método main e dentro do mesmo faça com que 
a mensagem gerada pelo método toString() seja 
impressa na tela. 
 
 
 
 
 47 
16) Crie uma classe Java chamada Pessoa com os seguintes 
atributos privados: 
- nome; 
- Data de Nascimento; 
 Crie os métodos necessários para acessar estes 
atributos. Crie também um método chamado "informarIdade", 
este método deve imprimir na tela a idade desta pessoa em 
anos, meses e dias. 
 Crie um método main para criar um objeto da classe 
Pessoa, inicie os atributos "nome" e "Data de nascimento" e 
em seguida chame o método "informarIdade" para que o mesmo 
informe a idade desta Pessoa. 
 
 
17) Crie uma classe Java para um Celular, com os seguintes 
atributos: modelo (String) e número (int). 
- Faça o encapsulamento destes atributos; 
- Faça a sobrecarga do método que irá alterar o 
valor do atributo número, permitindo que o 
programador informe uma string ou um inteiro; 
- Faça a sobrescrita do método correto da classe 
Object para retornar uma string que representa a 
concatenação dos atributos da classe.

Continue navegando