Um dos principais pilares que sustentam a estrutura do Java é a Orientação a Objetos (OO), uma abordagem de programação que modela software em torno de objetos e suas interações.
Neste artigo, você vai conhecer um pouco os conceitos fundamentais da Orientação a Objetos com Java, e como aplicá-la em práticas avançadas de desenvolvimento.
Conceitos Básicos da Orientação a Objetos
Na Orientação a Objetos, tudo é considerado um objeto. Um objeto pode ser uma representação de qualquer entidade do mundo real ou virtual e possui características (dados) e comportamentos (métodos). Os principais conceitos da OO incluem:
- Herança
- Polimorfismo
- Encapsulamento
- Abstração
Vou descrever um pouco de cada um deles e demonstrar alguns exemplos de códigos para ficar mais fácil a compreensão:
1º Herança
A herança é um dos pilares fundamentais da programação orientada a objetos e desempenha um papel essencial na linguagem de programação Java.
Ela é um conceito que permite criar uma nova classe, chamada de subclasse ou classe derivada, com base em uma classe existente, chamada de superclasse ou classe base. A ideia principal por trás da herança é a reutilização de código e a capacidade de criar uma hierarquia entre classes.
Hierarquia de Classes em Java
Na herança, a classe filha ou subclasse herda os atributos e métodos da classe pai ou superclasse. Isso significa que a subclasse possui todos os membros (métodos e atributos) da superclasse e pode adicionar novos membros ou modificar os existentes, seguindo o princípio da especialização.
Sintaxe de Herança em Java
Em Java, a herança é implementada usando extends. Por exemplo:
package br.com.virandoprogramador.heranca // Superclasse ou classe base public class Animal { public void emitirSom() { System.out.println("Som genérico de um animal."); } } // Subclasse ou classe derivada public class Cachorro extends Animal { public void latir() { System.out.println("Latindo como um cachorro."); } }
Neste exemplo, utilizamos a classe Cachorro que herda da classe Animal. Portanto, Cachorro tem acesso ao método emitirSom() da classe Animal.
Principais Conceitos de Herança em Java
Reutilização de Código
A herança permite a reutilização de código, uma vez que as classes filhas herdam os membros da classe pai. Isso evita a duplicação de código e promove um design mais limpo e modular.
Polimorfismo
O polimorfismo é um conceito relacionado à herança que permite que um objeto seja tratado como seu tipo base ou como um de seus subtipos. Isso significa que um objeto de uma subclasse pode ser referenciado como um objeto de sua superclasse.
Por exemplo:
Animal animal = new Cachorro(); animal.emitirSom(); // Chama o método emitirSom() da classe Cachorro
2º Polimorfismo
O polimorfismo é um conceito fundamental da programação orientada a objetos que permite que objetos de diferentes classes sejam tratados de maneira uniforme através de uma interface comum. Isso significa que um objeto pode ter várias formas e comportamentos diferentes, dependendo do contexto em que é usado.
Existem dois tipos principais de polimorfismo em Java: polimorfismo de sobrecarga (ou sobrecarga de método) e polimorfismo de sobreposição (ou sobrescrita de método).
Polimorfismo de Sobrecarga (Overload)
A sobrecarga ocorre quando duas ou mais funções têm o mesmo nome, mas parâmetros diferentes (tipo, número ou ordem de parâmetros). Em tempo de compilação, o compilador determina qual método chamar, com base nos argumentos fornecidos.
Exemplo de sobrecarga de método:
package br.com.virandoprogramador.polimorfismo public class Exemplo { public int somar(int a, int b) { return a + b; } public double somar(double a, double b) { return a + b; } }
No exemplo acima, há dois métodos somar, um para somar inteiros e outro para somar números decimais (double). Isso demonstra como o polimorfismo de sobrecarga permite a criação de métodos com o mesmo nome, mas com diferentes parâmetros.
Polimorfismo de Sobreposição (Override)
A sobreposição ocorre quando uma subclasse fornece uma implementação específica para um método que já está presente em sua superclasse. A assinatura do método (nome, tipo e número de parâmetros) deve ser exatamente a mesma na classe pai e na classe filha.
Exemplo de sobreposição de método:
package br.com.virandoprogramador.polimorfismo // Classe Pai public class Animal { public void fazerSom() { System.out.println("Som genérico de um animal."); } } // Subclasse public class Cachorro extends Animal { @Override public void fazerSom() { System.out.println("Latindo como um cachorro."); } }
Nesse exemplo, a classe Cachorro sobrepõe o método fazerSom da classe Animal. Quando um objeto da classe Cachorro é criado e o método fazerSom é chamado, ele executa a implementação específica da classe Cachorro.
Utilizando Polimorfismo em Java
package br.com.virandoprogramador.polimorfismo public class TestePolimorfismo { public static void main(String[] args) { Animal animal1 = new Cachorro(); Animal animal2 = new Gato(); animal1.fazerSom(); // Chama o método fazerSom() da classe Cachorro animal2.fazerSom(); // Chama o método fazerSom() da classe Gato } }
Neste exemplo, tanto animal1 quanto animal2 são referências do tipo Animal, mas apontam para instâncias de diferentes subtipos (uma para Cachorro e outra para Gato). Quando o método fazerSom() é chamado, o comportamento específico de cada classe é executado, de acordo com a sobreposição do método na subclasse.
O polimorfismo é um conceito poderoso que oferece flexibilidade e extensibilidade ao código, permitindo que programas em Java sejam mais genéricos e adaptáveis a mudanças. Ele desempenha um papel significativo no desenvolvimento de sistemas mais modulares e fáceis de manter.
3º Encapsulamento
O encapsulamento é um dos princípios fundamentais da programação orientada a objetos (POO) e desempenha um papel crucial na linguagem de programação Java. É um conceito que visa ocultar os detalhes de implementação de uma classe, permitindo o acesso controlado aos seus membros (atributos e métodos).
Isso é alcançado por meio do uso de modificadores de acesso, como public, private, protected e default (sem especificação), que determinam a visibilidade dos membros de uma classe.
Modificadores de Acesso em Java
- public: Os membros marcados como public podem ser acessados de qualquer lugar, ou seja, por outras classes e pacotes. Por exemplo:
public class Exemplo { public int valorPublico; }
private: Os membros marcados como private só podem ser acessados dentro da própria classe. Eles não são visíveis fora da classe:
package br.com.virandoprogramador.encapsulamento public class Exemplo { private int valorPrivado; // Métodos para acessar o valorPrivado de forma controlada public int getValorPrivado() { return valorPrivado; } public void setValorPrivado(int novoValor) { this.valorPrivado = novoValor; } }
O encapsulamento é frequentemente associado ao uso de métodos especiais chamados de “métodos acessores” (getters) e “métodos modificadores” (setters), que permitem acesso controlado aos atributos privados de uma classe.
- Métodos Acessores (Getters): São métodos públicos usados para recuperar o valor de um atributo privado.
- Métodos Modificadores (Setters): São métodos públicos usados para modificar ou atribuir um novo valor a um atributo privado. Eles podem realizar validações ou operações antes de alterar o estado do objeto.
Exemplo de Encapsulamento em Java
package br.com.virandoprogramador.encapsulamento public class ContaBancaria { private double saldo; // Método para depositar dinheiro public void depositar(double valor) { if (valor > 0) { saldo += valor; System.out.println("Depósito de " + valor + " realizado com sucesso."); } else { System.out.println("Valor inválido para depósito."); } } // Método para sacar dinheiro public void sacar(double valor) { if (valor > 0 && valor <= saldo) { saldo -= valor; System.out.println("Saque de " + valor + " realizado com sucesso."); } else { System.out.println("Valor inválido para saque ou saldo insuficiente."); } } // Método para obter o saldo public double getSaldo() { return saldo; } }
4º Abstração
A Abstração é um dos pilares da programação orientada a objetos que permite modelar objetos do mundo real em um sistema de software, enfocando apenas nos detalhes relevantes para a aplicação e ocultando os detalhes desnecessários.
Exemplo de Abstração em Java
Vamos considerar um exemplo de abstração relacionado a veículos.
package br.com.virandoprogramador.abstracao // Classe abstrata representando um Veículo public abstract class Veiculo { private String marca; private String modelo; public Veiculo(String marca, String modelo) { this.marca = marca; this.modelo = modelo; } // Método abstrato para obter a descrição do veículo public abstract String descricao(); // Métodos getters e setters para marca e modelo }
Neste exemplo, Veiculo é uma classe abstrata que encapsula atributos comuns a todos os veículos, como marca e modelo. Ela também possui um método abstrato descricao() que será implementado pelas subclasses concretas.
package br.com.virandoprogramador.abstracao // Subclasse Carro que estende Veiculo public class Carro extends Veiculo { private int numeroPortas; public Carro(String marca, String modelo, int numeroPortas) { super(marca, modelo); this.numeroPortas = numeroPortas; } @Override public String descricao() { return "Carro: Marca - " + getMarca() + ", Modelo - " + getModelo() + ", Número de Portas - " + numeroPortas; } }
A classe Carro é uma implementação concreta de Veiculo que adiciona seu próprio atributo numeroPortas. Além disso, ela sobrescreve o método descricao() para fornecer uma descrição específica para carros.
Na prática, a abstração é implementada por meio de classes e interfaces, onde são definidos métodos e atributos que representam o comportamento e características genéricas de um grupo de objetos relacionados. Uma classe abstrata pode conter métodos abstratos, que são declarados sem implementação e devem ser definidos por suas subclasses concretas.
Por exemplo, ao modelar um sistema de veículos, a abstração permite criar uma classe base chamada Veiculo que contém atributos comuns a todos os tipos de veículos (como marca e modelo) e métodos genéricos (por exemplo, um método para obter a descrição do veículo). As subclasses concretas, como Carro, estendem essa classe abstrata Veiculo e implementam suas características específicas.
Quais são as linguagens Orientadas a Objetos?
Existem várias linguagens de programação que seguem os princípios e paradigmas da programação orientada a objetos (POO). Algumas das linguagens mais populares e amplamente utilizadas que adotam esse paradigma são:
- Java
- C#
- C++
- Python
- Ruby
- PHP
- Swift e Objective-C
Existem muitas outras que utilizam esse paradigma, em nosso exemplo utilizamos Java pelo fato de ser o nosso foco principal aqui no portal, porém você pode utilizar os mesmos conceitos de Orientação a Objetos em várias linguagens, o conceito sempre será o mesmo, o que muda é mais a sintaxe de código.
Encerramento sobre o assunto
A programação orientada a objetos (POO) é um paradigma de programação poderoso e amplamente utilizado na indústria de software. Ela se baseia em conceitos-chave, como classes, objetos, herança, polimorfismo e encapsulamento, para estruturar o código de maneira mais organizada, reutilizável e modular.