[JAVA] Trabalhando com Classes Abstratas


É muito simples trabalhar com clases abstratas. Uma classe abstrata nada mais é do que uma especificação conceitual para outras classes. O que isso que dizer? Que nunca iremos instanciá-la. Ela apenas fornece um modelo para geração de outras classes. Esta nunca está completa, ou seja, servirá apenas para criação de funcionalidades genéricas de casses filhas. Podemos também chamar as classes abstratas de super classe.

Sem complicações, o basico é isso! Disponibilizei no final do post um link para download das classes exemplificadas aqui.

Agora a parte prática. Todos os arquivos poderão ficar no mesmo nível de diretório.
A hierarquia das classes deste exemplo estão da seguite forma (somente estrutura, e não definição de atributos e métodos):

Java - Herança

Sabemos que Pessoa Física e Pessoa Jurídica possuem o atributo nome como uma informação em comum. Dentre dezenas de informações, a mais comentada que gera uma grande diferença entre as duas são CPF para Física e CNPJ para Jurísica. Por esse motivo (também) que definimos classes abastratas para nossos projetos. Ao invés de definirmos o atributo nome para as duas classes (gerando redundância), criamos uma classe abstrata e inserimos um atributo nome dentro dela, então herdamos as propriedades para nossas classes filhas Fisica e Juridica. Aí sim definimos dentro de Fisica o atributo CPF e para Juridica o CNPJ. O atributo nome vem automaticamente pela super classe.

Abaixo a super classe, ou a classe abstrata. O tipo protected define que somente ela e as derivadas poderão ter acesso aos atributos/métodos. Temos dois construtores e um método que retorna o nome. O método getNome é public porque precisará ser acessada direto na instância, ou seja, não há implementação deste método nas classes filhas. Veja a definição da classe, como abstract.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public abstract class Pessoa{
	protected String xNome;
 
	// CONSTRUTORES
	protected Pessoa(){
		xNome = "Sem nome";
	}
 
	protected Pessoa(String nome){
		xNome = nome;
	}
	// FIM CONSTRUTORES	
 
	public String getNome(){
		return xNome;
	}
}

Abaixo a classe filha Fisica. Repare a instrução extends na definição da classe, linha 1. O segredo é esse. Vai herdar da classe Pessoa suas características. Foi criado apenas os contrutores com chamadas à super classe. O construtor Fisica(String nome) por exemplo, vai herdar o comportamento do construtuor do mesmo tipo na classe Pessoa. O método getCPF foi implementado somente nesta classe, já que é uma característica somente de pessoa física. Não foi implementado o método getNome pelo simples fato de ter herdado da classe pai. Ao instanciarmos essa classe Fisica, poderemos usar sem problemas o método getNome como se fosse da classe filha.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Fisica extends Pessoa{
 
	private String xCPF;
 
	// CONSTRUTORES		
	public Fisica(){
		super();
	}
 
	public Fisica(String nome){
		super(nome);
	}
 
	// FIM CONSTRUTORES		
 
	public String getCPF(){
		return  xCPF;
	}
}

Abaixo a classe Juridica. Temos apenas duas diferenças da classe Fisica. Uma delas é obrigatória, ou seja, a definição do método getCNPJ, afinal, somente empresas possuem CNPJ. Isso explica o motivo de não ter sido implementado na classe Fisica, pois lá temos o método getCPF, ou também não ter sido implementado na super classe Pessoa, senão todas as classes teriam que herdar esse método, então daria errado nosso projeto. A segunda diferença está na definição do método getNome. Mas você pergunta, por que implementei esse método se já possue na classe Pessoa? Porque temos a flexibilidade de redefinir ou complementar um método da super classe, apenas implementando-á com o mesmo nome. Inseri o getNome apenas a fim de exemplo, pois no final vai fazer a mesma coisa, por que? Porque estou solicitando da super classe o nome da Pessoa, através do super.getNome. Eu poderia muito bem redefinir esse método fazendo centenas de linhas de códigos, fique livre.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class Juridica extends Pessoa{
 
	private String xCNPJ;
 
	// CONSTRUTORES		
	public Juridica(){
		super();
	}
 
	public Juridica(String nome){
		super(nome);
	}
 
	// FIM CONSTRUTORES		
 
	public String getCNPJ(){
		return  xCNPJ;
	}
 
	public String getNome(){
		return super.getNome();
	}
}

Por fim a classe Principal, nada de especial aqui, mas não pude deixar de codificar o exemplo por completo. Instanciamos um objeto do tipo Fisica e outro do tipo Juridica. Ao instanciar do tipo Fisica eu usei o construtor que já define um conteúdo para o atributo nome, imprimo no console seu nome e seu CPF (que não foi definido). O objeto do tipo Juridica usei o construtor padrão, sem enviar qualquer informação ao método, deixando assim o nome como “Sem nome”, regra implementada lá na super classe Pessoa (volte lá e veja). Imprimimos no console o nome e o CNPJ, que também não foi definido neste projeto.

1
2
3
4
5
6
7
8
9
10
11
class Principal{
	public static void main(String[] args){
		Fisica pessoa1 = new Fisica("Daniel");
		System.out.println (pessoa1.getNome());
		System.out.println (pessoa1.getCPF());
 
		Juridica pessoa2 = new Juridica();
		System.out.println (pessoa2.getNome());
		System.out.println (pessoa2.getCNPJ());
	}
}

Por mais que eu procure simplificar ao máximo os exemplos, sempre vai ocorrendo as possíveis dúvidas dos leitores e acabo escrevendo mais do que deveria, mas nada é demais. Espero que tenha esclarecido. Abaixo download de todos os arquivos.

Download dos arquivos deste exemplo.

, , ,

  1. #1 by Rodrigo on 07/05/2009 - 23:34

    Tenho algumas dúvidas! Agora que temos essas classes, precisamos criar cliente e fornecedor, por sua vez um cliente pode ser PessoaFisica ou Juridica e um fornecedor também. Como fazer essa implementação e ainda persistir com o Hibernate! E como obter uma ainda um lista dos clientes e essa lista poder ter clientes fisicos e juridicos para eu verificar com instanceof? Agraço sua ajuda!

  2. #2 by Daniel Accorsi on 08/05/2009 - 15:55

    @Rodrigo
    Então Rodrigo, é uma dúvida comum essa, quando falamos em cliente/fornecedor/pf/pj. Mas você pode fazer uma herança como acima demonstrado, normal. Sobre cliente/fornecedor para cada tipo de pessoa, você pode fazer: relacionamento de Pessoa com cliente e outro de Pessoa com fornecedor. Conseguiu pegar???

    Referente ao Hibernate, não sei com exatidão, de cabeça! Mas de uma conferida na documentação original, é mais confiável: https://www.hibernate.org/5.html

  3. #3 by Regis on 24/06/2009 - 15:43

    Daniel,

    Primeiro gostaria de parabenizá-lo! O exemplo e a didática estão jóia neste artigo.

    Além de não permitir ser instanciada, qual é a vantagem em se utilizar classes abstratas frente a herança comum?

    Abraço

  4. #4 by Daniel Accorsi on 24/06/2009 - 23:51

    Olá Regis,
    Obrigado pelo elogio!
    Não sei se entendi bem sua pergunta, mas vou tentar responder. O uso mais comum de uma classe abstrata é a possibilidade de oferecer uma estrutura básica para ser implementada em várias outras subclasses através da herança. Por isso que uma classe abstrata não pode ser instanciada. Defina sua regra de negocio na superclasse e implemente seus métodos nas subclasses.

    Não sei se era isso, mas qualquer coisa só responder aqui.

  5. #5 by Ricardo on 23/10/2009 - 18:56

    Olá Daniel primeiramente gostaria de parabenizá-lo pelo tutorial que ficou muito bom mesmo. Mas eu só fiquei com uma dúvida aqui, o atributo nome não será compartilhado pelas as instâncias de Pessoa Física e Jurídica não né? O que eu estou querendo dizer é se eu tenho uma instância de Pessoa Física e atribuo o nome de Mario, por exemplo, a outra instância de Pessoa Juridica que eu tiver vai poder ter qq outro nome?

  6. #6 by Ricardo on 06/02/2010 - 19:47

    Ricardo : Olá Daniel primeiramente gostaria de parabenizá-lo pelo tutorial que ficou muito bom mesmo. Mas eu só fiquei com uma dúvida aqui, o atributo nome não será compartilhado pelas as instâncias de Pessoa Física e Jurídica não né? O que eu estou querendo dizer é se eu tenho uma instância de Pessoa Física e atribuo o nome de Mario, por exemplo, a outra instância de Pessoa Juridica que eu tiver vai poder ter qq outro nome?

    Daniel Accorsi : Olá Regis,
    Obrigado pelo elogio!
    Não sei se entendi bem sua pergunta, mas vou tentar responder. O uso mais comum de uma classe abstrata é a possibilidade de oferecer uma estrutura básica para ser implementada em várias outras subclasses através da herança. Por isso que uma classe abstrata não pode ser instanciada. Defina sua regra de negocio na superclasse e implemente seus métodos nas subclasses.
    Não sei se era isso, mas qualquer coisa só responder aqui.

    Daniel Accorsi : Olá Regis,
    Obrigado pelo elogio!
    Não sei se entendi bem sua pergunta, mas vou tentar responder. O uso mais comum de uma classe abstrata é a possibilidade de oferecer uma estrutura básica para ser implementada em várias outras subclasses através da herança. Por isso que uma classe abstrata não pode ser instanciada. Defina sua regra de negocio na superclasse e implemente seus métodos nas subclasses.
    Não sei se era isso, mas qualquer coisa só responder aqui.

    @ Daniel Accorsi

    Daniel Accorsi : Olá Regis,
    abstrata é a possibilidade de oferecer uma estrutura básica para ser implementada em várias outras subclasses através da herança. Por isso que uma classe abstrata não pode ser instanciada. Defina sua regra de negocio na superclasse e implemente seus métodos nas subclasses.
    Não sei se era isso, mas qualquer coisa só responder aqui.

    @Regis

  7. #7 by Anderson on 17/06/2010 - 12:26

    Parabéns pelo artigo…Entendi perfeitamente o conceito…
    mas estou usando o JCreator e os codigos estão exatamente iguais aos que vc passou…Porque não funciona???
    precisa fazer algum import que não estou fazendo?

    Att anderson

(não será publicado)