Os pilares da orientação a objetos \| TreinaWeb               Promoção no ar   Matricule-se agora e garanta **54% de desconto**  

  Termina em   Tempo restante da oferta: 16 Horas 

 50 Min 

 14 Seg 

   Tempo restante da oferta: 16 50 14 

  [Assinar →](https://www.treinaweb.com.br/checkout/pagamento/plano/anual?cupom=TW-SCLIENTE26) 

   [                ](https://www.treinaweb.com.br)  Explorar  

 [ Quanto custa? ](#assinatura) [ FAQ ](https://www.treinaweb.com.br#faq) [Matricule-se](#assinatura) [ Entrar ](https://www.treinaweb.com.br/login) 

     [ Início ](https://www.treinaweb.com.br) [ Artigos ](https://www.treinaweb.com.br/blog) Os pilares da orientação a objetos  [ Orientação a Objetos ](https://www.treinaweb.com.br/blog/categoria/orientacao-a-objetos) 

# Os pilares da orientação a objetos

 O paradigma orientado a objetos é um dos mais utilizados no mercado de trabalho. Neste artigo, veremos os pilares da orientação a objetos.

 [ Cleber Campomori ](https://www.treinaweb.com.br/blog/autor/cleber-campomori) 8 anos atrás

  ![](https://dkrn4sk0rn31v.cloudfront.net/uploads/2018/10/15020508/rsz_bridge-246913_1920.png)  

O paradigma orientado a objetos é um dos paradigmas mais utilizados no mercado de trabalho. Além de ser um dos primeiros paradigmas com o qual nós temos contato quando começamos a estudar desenvolvimento de software, a maioria das linguagens utilzadas pela indústria em geral possui uma forte base orientada a objetos, o que faz com que seja essencial o domínio deste paradigma. Neste artigo, vamos verificar quais são os pontos principais do paradigma orientado a objetos.

 [ ![](https://dkrn4sk0rn31v.cloudfront.net/uploads/2023/06/ebook-logica-de-programacao.jpg) ](https://www.treinaweb.com.br/ebook/logica-de-programacao/)

Caso você esteja iniciando na área de desenvolvimento, indico também a leitura de nosso [guia de introdução à programação](https://www.treinaweb.com.br/blog/guia-de-introducao-a-programacao/ "guia de introdução à programação").

[  ![PHP - Gerenciador de dependências Composer](https://d2knvm16wkt3ia.cloudfront.net/assets/svg-icon/composer.svg)   Curso PHP - Gerenciador de dependências Composer Conhecer o curso ](https://www.treinaweb.com.br/curso/php-gerenciador-de-dependencias-composer)

## Classes e objetos

Em linguagens orientadas a objeto, nós organizamos a maior parte do nosso código em estruturas chamadas *classes*.

Você pode entender uma *classe* como sendo inicialmente um *molde*, molde este que geralmente representa alguma estrutura do mundo real com a qual nosso código terá que lidar. Vamos imaginar que estejamos trabalhando com uma aplicação que lida com carros…

Provavelmente, nossa aplicação irá lidar com carros e, por causa disso, precisaremos de um molde para definirmos o que é um carro dentro do nosso código. Esse molde seria responsável por estabelecer *o que é um carro* e *o que pode fazer um carro*.

Se pararmos para pensar, nós podemos falar que um carro pode ser caracterizado pelos seguintes itens:

- Marca;
- Modelo;
- Cor;
- Placa;
- E várias outras características…

Também podemos dizer que um carro pode ter as seguintes ações:

- Ligar;
- Acelerar;
- Desligar;
- E várias outras ações…

Veja que, quando falamos *do que um carro é*, estamos falando de suas características, ou seja: falamos do que caracteriza e define um determinado carro. Já quando falamos *do que um carro pode fazer*, estamos falando das ações que um carro pode desempenhar.

Trazendo para termos técnicos, nós podemos chamar as características do carro de **atributos**, euquanto nós chamamos as ações de **métodos**. No final, os métodos e atributos ficam agrupados em uma classe.

Nós podemos representar estes atributos e métodos através de uma linguagem de modelagem chamada UML (*Unified Modeling Language*). A UML prevê alguns diagramas que visam auxiliar o processo de modelagem de um software. Entre estes diagramas, nós temos justamente o *diagrama de classes*.

A classe *Carro*, se fosse representada pelo diagrama de classes UML, poderia ficar da seguinte maneira:

![Diagrama da classe carro](https://dkrn4sk0rn31v.cloudfront.net/2018/10/15104222/5bc3da62bcd15.png)

Perceba que a partir deste *molde*, nós podemos especificar vários carros… Poderíamos ter um Fiat Línea prata com a placa ABC-1234, um Volswagen Gol preto com a placa DEF-4567 ou mesmo um Hyundai HB20 branco com a placa GHI-8901… Todos eles são carros, já que derivam do mesmo *molde*: todos eles têm marca, modelo, cor e placa, além de poderem ser ligados, desligados, freados e acelerados, atributos e métodos todos estabelecidos pela classe *Carro*. Nesse caso, o Fiat Línea, o Volkswagen Gol e o Hyundai HB20 são **objetos**, pois foram “fabricados” a partir do molde que definimos, que é a classe *Carro*. Objetos são como *variáveis* que criamos para utilizar as nossas classes, seja para definir seus atributos, como também para invocar seus métodos. É o encadeamento coordenado entre escritas e leituras de atributos com a invocação de métodos que dá a tônica de uma aplicação escrita com uma linguagem orientada a objetos.

Se fôssemos utilizar o [Java](https://www.treinaweb.com.br/blog/o-que-e-e-como-comecar-com-java/ "O que é e como começar com Java?") para representar nossa classe e nossos objetos de uma maneira primitiva, teríamos o código abaixo.

```java
// Pacotes e demais estruturas omitidas para clareza...
public class Carro {
    public String modelo;
    public String marca;
    public String cor;
    public String placa;

    public void ligar() {
        System.out.println("O veículo ligou!");
    }

    public void desligar() {
        System.out.println("O veículo desligou!");
    }
}

// ...
Carro gol = new Carro();
gol.modelo = "Gol";
gol.marca = "Volkswagen";

Carro linea = new Carro();
linea.modelo = "Línea";
linea.marca = "Volkswagen";

gol.ligar();
gol.desligar();
linea.ligar();
linea.desligar();

```

No exemplo acima, temos a classe `Carro` fazendo o papel de nosso molde. As variáveis `gol` e `linea` são objetos que são do tipo `Carro` ou, utilizando os termos técnicos corretos, `gol` e `linea` são instâncias da classe `Carro`. Por derivarem da classe `Carro`, estes objetos têm todos os atributos e métodos previstos pela classe `Carro`.

## Encapsulamento

Ainda levando em consideração o exemplo com a classe *Carro*, poderíamos imaginar um indicador para verificarmos se o carro está ligado ou não. Isso até daria mais “qualidade” à nossa classe *Carro*: nós poderíamos, por exemplo, garantir que o carro só pudesse ser acelerado ou freado caso estivesse ligado. Esse indicador ainda poderia ser modificado pelos métodos `ligar()`e `desligar()`…

Partindo dessa idéia, nossa classe `Carro` ficaria da seguinte maneira:

```java
public class Carro {

    public String modelo;
    public String marca;
	// ...
    public boolean ligado;	

	public Carro() {
		ligado = false;
	}

    public void ligar() {
		ligado = true;
        System.out.println("O veículo ligou!");
    }

    public void desligar() {
		ligado = false;
        System.out.println("O veículo desligou!");
    }
}

```

Veja que, além de adicionarmos um atributo chamado `ligado` do tipo booleano (`true`para ligado ou `false` para desligado), nós temos ainda o trecho de código abaixo:

```java
public Carro() {
	ligado = false;
}

```

Esse trecho de código é um *construtor*. O construtor é invocado quando inicializamos um objeto a partir de uma classe. Nós, de maneira geral, invocamos o construtor quando chamamos a criação da instância com a palavra-chave `new`. Sendo assim, quando temos o código abaixo…

```java
Carro gol = new Carro();

```

… nós estamos justamente chamando este método construtor. Ao reescrevermos este método, estamos impondo uma “personalização” na inicialização dos objetos a partir da classe `Carro`: todo carro será criado já possuindo o indicador `ligado` como `false`, ou seja, o carro já começa como desligado por padrão.

Agora, poderíamos definir, por exemplo, um método chamado `acelerar()` em nosso `Carro`. Nós podemos verificar o atributo `ligado` para “controlar” melhor este método: um carro, obviamente, só pode ser acelerado caso esteja ligado.

Nosso código de exemplo ficaria da seguinte maneira:

```java
public class Carro {

    public String modelo;
    public String marca;
    // ...
    public boolean ligado;	

	public Carro() {
		ligado = false;
	}

    public void ligar() {
		ligado = true;
        System.out.println("O veículo ligou!");
    }

    public void desligar() {
		ligado = false;
        System.out.println("O veículo desligou!");
    }

	public void acelerar() {
		if (!ligado){
			throw new Exception("O carro não pode ser acelerado, pois ele está desligado."); // Erro: o carro está desligado!
		}
		System.out.println("O carro foi acelerado");
	}
}

```

Assim, poderíamos ter a nossa classe `Carro` sendo utilizada da seguinte maneira:

```java
Carro gol = new Carro();
System.out.println(gol.ligado); // Vai imprimir "false" por causa do construtor personalizado
gol.modelo = "Gol";
gol.marca = "Volkswagen";
// gol.acelerar(); Se essa linha for descomentada, o código gerará um erro, pois estamos tentando acelerar um carro desligado
gol.ligar();
System.out.println(gol.ligado); // Vai imprimir "true", pois o método ligar() foi chamado
gol.acelerar();
gol.desligar();
System.out.println(gol.ligado); // Vai imprimir "false", pois o método desligar() foi chamado

```

Aparentemente, nossa classe `Carro` está funcionando corretamente. Mas, temos um problema: o atributo `ligado` é acessível para todo mundo, da mesma maneira que os atributos `modelo` e `marca` por exemplo. Isso quer dizer que nós podemos “deturpar” o comportamento da classe `Carro`… Nós poderíamos, por exemplo, alterar manualmente o conteúdo do atributo `ligado` antes de chamarmos o método `ligar()`, permitindo acelerar um carro que estivesse em tese desligado:

```java
Carro gol = new Carro();
System.out.println(gol.ligado); // Vai imprimir "false" por causa do construtor personalizado
gol.ligado = true; // Atributo que define se o carro está ligado ou não alterado "na mão"
gol.acelerar(); // Agora a linha não causará erro, mesmo que o método ligar() não tenha sido chamado

```

Isso certamente é uma situação problemática, pois agora nosso carro dá uma brecha para funcionar de maneira diferente de como ele foi planejado.

Para corrigirmos isso, precisamos recorrer a um pilar da orientação a objetos: o *encapsulamento*. O encapsulamento visa *esconder* atributos e métodos de nossas classes que não deveriam ser acessados por outras estruturas. É exatamente o que precisamos: o atributo `ligado` deveria ser acessível em tese só pela própria classe `Carro`, o que permitiria somente aos métodos `ligar()` e `desligar()` alterarem o indicador de funcionamento do carro da maneira correta. Isso evitaria que nós acessássemos o atributo do lado de fora, causando a falha no código que estamos discutindo aqui.

O encapsulamento nas linguagens orientadas a objetos é definido através de algo que chamamos de *atributo de visibilidade*. Estes atributos de visibilidade estabelecem justamente o quão acessível nossos atributos e métodos são com relação às demais estruturas do nosos código. De maneira geral, temos três atributos de visibilidade básicos e comuns às linguagens orientadas a objeto em geral:

- `public`: a estrutura é visível a partir de qualquer lugar no código, inclusive em outras classes fora a classe que define o atributo ou método em si;
- `private`: a estrutura é visível somente pela classe que define a estrutura em si. Estruturas externas, como outras classes, não conseguem acessar o método ou atributo que esteja marcado com este atributo de visibilidade;
- `protected`: a estrutura é visível somente na classe-mãe e nas classes-filhas.

Se considerarmos a nossa classe `Carro`, podemos ver que o problema relatado acontece porque o atributo `ligado` está definido como `public`, o tornando acessível em qualquer lugar. Vimos que esse é o problema, pois o atributo `ligado` não poderia ser acessível a partir de qualquer lugar: ele deveria ser acessível somente dentro dos métodos `ligar()` e `desligar()`, ambos dentro da classe `Carro`. O nosso atributo `ligado` não está encapsulado.

[  ![IA Para Devs -  Spec Driven Development](https://d2knvm16wkt3ia.cloudfront.net/assets/svg-icon/ia-para-devs.svg)   Curso IA Para Devs - Spec Driven Development Conhecer o curso ](https://www.treinaweb.com.br/curso/ia-para-devs-spec-driven-development)

Poderíamos o encapsular se o tornássemos `private`, fazendo com que ele fosse acessível somente dentro da classe `Carro`.

```java
public class Carro {

    public String modelo;
    public String marca;
    // ...
    private boolean ligado;	

	public Carro() {
		ligado = false;
	}

    public void ligar() {
		ligado = true;
        System.out.println("O veículo ligou!");
    }

    public void desligar() {
		ligado = false;
        System.out.println("O veículo desligou!");
    }

	public void acelerar() {
		if (!ligado){
			throw new Exception("O carro não pode ser acelerado, pois ele está desligado."); // Erro: o carro está desligado!
		}
		System.out.println("O carro foi acelerado");
	}
}

```

Assim, o erro que víamos antes não acontecerá mais, pois o atributo `ligado` agora só é acessível dentro da própria classe `Carro`.

```java
Carro gol = new Carro();
gol.ligado = true; // Essa linha causará um erro de compilação, pois o atributo "ligado" não é mais acessível externamente

```

Agora, podemos dizer que o atributo `ligado` da classe `Carro` está encapsulado.

Se quiséssemos pelo menos ler o valor do atributo `ligado` externamente (já que alterá-lo externamente estaria completamente errado), poderíamos criar um método que devolvesse o valor do atributo `ligado`.

```java
public class Carro {

    public String modelo;
    public String marca;
    // ...
    public boolean ligado;	

	public Carro() {
		ligado = false;
	}

    public void ligar() {
		ligado = true;
        System.out.println("O veículo ligou!");
    }

    public void desligar() {
		ligado = false;
        System.out.println("O veículo desligou!");
    }

	public void acelerar() {
		if (!ligado){
			throw new Exception("O carro não pode ser acelerado, pois ele está desligado."); // Erro: o carro está desligado!
		}
		System.out.println("O carro foi acelerado");
	}

	public boolean estaLigado() {
		return ligado;
	}
}

```

Com o método acima, poderíamos pelo menos verificar externamente se o carro está ligado ou desligado.

```java
Carro gol = new Carro();
System.out.println(gol.estaLigado()); // Vai imprimir "false" por causa do construtor personalizado
gol.modelo = "Gol";
gol.marca = "Volkswagen";
gol.ligar();
System.out.println(gol.estaLigado()); // Vai imprimir "true", pois o método ligar() foi chamado
gol.acelerar();
gol.desligar();
System.out.println(gol.estaLigado()); // Vai imprimir "false", pois o método desligar() foi chamado

```

Este tipo de método é geralmente chamado de *método de acesso*, já que ele provê um tipo de acesso indireto a um atributo encapsulado. Com relação ao encapsulamento, nós temos dois tipos de métodos de acesso basicamente:

- `get`: métodos que permitem ver o valor de um atributo;
- `set`: métodos que permitem alterar o valor de um atributo.

Nós poderíamos falar que o método `estaLigado()` é um método `get`, pois ele permite a nós lermos algo que está encapsulado dentro da classe `Carro`.

É uma prática recorrente em linguagens orientadas a objeto (principalmente no Java) envolver todos os atributos com métodos de acesso do tipo `get` e `set`, evitando o acesso direto aos atributos. Apesar de ser uma prática comum, é importante dizer que só o fato de utilizarmos métodos de acesso não garante o encapsulamento de nenhuma estrutura. O que garante este encapsulamento é a definição de visibilidade correta de cada um dos atributos e métodos e o estabelecimento dos métodos de acesso de maneira correta. Por exemplo: não criamos um método `set` para o atributo `ligado`, pois ele só pode ser alterado pela própria classe.

Se fôssemos aplicar esta regra a nossa classe `Carro`, nós teríamos o seguinte código:

```java
public class Carro {

    private String modelo;
    private String marca;
	// ...
    public boolean ligado;	

	public void setModelo(String modelo) {
		this.modelo = modelo;
	}

	public String getModelo() {
		return modelo;
	}

	public void setMarca(String marca) {
		this.marca = marca;
	}

	public String getMarca() {
		return marca;
	}

	public Carro() {
		ligado = false;
	}

    public void ligar() {
		ligado = true;
        System.out.println("O veículo ligou!");
    }

    public void desligar() {
		ligado = false;
        System.out.println("O veículo desligou!");
    }

	public void acelerar() {
		if (!ligado){
			throw new Exception("O carro não pode ser acelerado, pois ele está desligado."); // Erro: o carro está desligado!
		}
		System.out.println("O carro foi acelerado");
	}

	public boolean estaLigado() {
		return ligado;
	}
}

```

## Herança

O reaproveitamento de código e a possibilidade de se evitar código duplicado são objetivos das linguagens orientadas a objetos. Vamos imaginar que agora nós precisamos criar uma classe para definir um outro tipo de veículo, como uma bicicleta. Uma bicicleta possui atributos em comum com um carro: ambos possuem marca e modelo, por exemplo. Além disso, ambos não deixam de ser um tipo de veículo.

Se fôssemos escrever o código para definição da classe `Bicicleta` sem considerar a classe `Carro`, nós teríamos o seguinte código:

```java
public class Bicicleta {

    private String modelo;
    private String marca;

	public void setModelo(String modelo) {
		this.modelo = modelo;
	}

	public String getModelo() {
		return modelo;
	}

	public void setMarca(String marca) {
		this.marca = marca;
	}

	public String getMarca() {
		return marca;
	}

	public void acelerar() {
		System.out.println("A bicicleta foi acelerada.");
	}
}

```

Veja que acabamos duplicando todo o código relativo aos atributos `marca` e `modelo` nas classes `Carro` e `Bicicleta`, o que pode ser bem ruim em termos de manutenibilidade do código a longo prazo. Mas, nós temos uma maneira de evitar essa duplicidade: nós podemos utilizar o conceito de herança.

Nesse exemplo, se fôssemos aplicar o conceito de herança, nós teríamos três classes:

- A classe `Carro`, com tudo que um carro possui de características e ações;
- A classe `Bicicleta`, com tudo que uma bicicleta possui de características e ações;
- Uma nova classe chamada `Veiculo`, com tudo que existe de comum entre carros e bicicletas.

No exemplo acima, para que as classes `Carro` e `Bicicleta` conseguissem usufruir das estruturas comuns estabelecidas na classe `Veiculo`, elas precisariam herdar a classe `Veiculo`.

Poderíamos representar esta relação entre as classes `Veiculo`, `Carro` e `Bicicleta` com a UML da seguinte maneira:

![Diagrama de classes: Veiculo, Carro e Bicicleta](https://dkrn4sk0rn31v.cloudfront.net/2018/10/15104401/5bc40b6759d0e.png)

Também poderíamos definir as classes `Veiculo`, `Carro` e `Bicicleta` da seguinte maneira:

```java
public class Veiculo {

    private String modelo;
    private String marca;

	public void setModelo(String modelo) {
		this.modelo = modelo;
	}

	public String getModelo() {
		return modelo;
	}

	public void setMarca(String marca) {
		this.marca = marca;
	}

	public String getMarca() {
		return marca;
	}

	public void acelerar() {
		// ???
	}

}

public class Carro extends Veiculo {

    public boolean ligado;	

	public Carro() {
		ligado = false;
	}

    public void ligar() {
		ligado = true;
        System.out.println("O veículo ligou!");
    }

    public void desligar() {
		ligado = false;
        System.out.println("O veículo desligou!");
    }

	public void acelerar() {
		if (!ligado){
			throw new Exception("O carro não pode ser acelerado, pois ele está desligado."); // Erro: o carro está desligado!
		}
		System.out.println("O carro foi acelerado");
	}

	public boolean estaLigado() {
		return ligado;
	}
}

public class Bicicleta extends Veiculo {

	public void acelerar() {
		System.out.println("A bicicleta acelerou!");
	}

}

```

Veja que tudo que é comum entre as classes `Carro` e `Bicicleta` foi para a classe `Veiculo`. As classes `Carro` e `Bicicleta` estão agora herdando a classe `Veiculo` para reaproveitar estas estruturas comuns, além de que um carro e uma bicicleta são tipos de veículos. É importante que, quando formos empregar a herança, exista essa relação de “ser” ou “estar” entre as classes.

Nesse caso, nós podemos fazer com que `Carro` herde `Veiculo` porque um carro é um veículo; assim como também podemos fazer com que `Bicicleta` herde `Veiculo`, pois uma bicicleta é um tipo de veículo. Com a herança, nós evitamos a duplicidade de código e facilitamos a manutenção, além de manter a coerência, desde que a regra do “ser/estar” seja devidamente implementada.

Quando temos a herança sendo utilizada, as classes podem assumir um dos dois papéis:

- Classe-mãe, classe-base ou super-classe: é a classe que serve de base para as demais classes. Em nosso exemplo, a classe `Veiculo` é uma super-classe;
- Classe-filha ou sub-classe: é a classe que herda outra determinada classe. No nosso exemplo, as classes `Carro` e `Bicicleta` são sub-classes.

## Abstração

Quando estamos lidando com a orientação a objetos, é muito comum que nós sempre tentemos escrever código baseado em abstrações, pois isso traz flexibilidade ao código.

No exemplo anterior, nós esbarramos em um problema de abstração: todo veículo é capaz de acelerar, independente de ser um carro ou bicicleta. Sendo assim, nós não podemos remover o método `acelerar()` da nossa classe `Veiculo`, já que todo veículo tem esse comportamento. Mas, a própria classe `Veiculo` não “sabe” como acelerar.

Quem sabe como acelerar é a classe `Carro`(que sabe como um carro acelera) e a classe `Bicicleta` (que sabe como uma bicicleta acelera). Para resolver esta situação, poderíamos tornar o método `acelerar()` abstrato: isso vai desobrigar a classe `Veiculo` a definir uma implementação para este método (já que a classe `Veiculo` não sabe como acelerar), mas obriga as classes-filha (no caso, as classes `Carro` e `Bicicleta`) a definirem seus comportamentos de aceleração.

Além disso, se pararmos para analisar, não faz sentido nós instanciarmos objetos a partir da classe `Veiculo`, já que ela serve somente como uma super-classe em nosso cenário. Nós poderíamos instanciar objetos a partir das classes `Carro` e `Bicicleta`, mas não a partir da classe `Veiculo`. Como queremos evitar que objetos sejam instanciados a partir da classe `Veiculo`, já que ela deve ser somente uma classe-base, também podemos definir a classe `Veiculo` como sendo uma classe abstrata.

O código ficaria da seguinte maneira:

```java
// Classe abstrata (não pode ser instanciada)
public abstract class Veiculo {

    private String modelo;
    private String marca;

	public void setModelo(String modelo) {
		this.modelo = modelo;
	}

	public String getModelo() {
		return modelo;
	}

	public void setMarca(String marca) {
		this.marca = marca;
	}

	public String getMarca() {
		return marca;
	}

	// Método abstrato: a classe Veiculo sabe que ela tem que acelerar, mas não sabe como fazer isso.
	// A responsabilidade passa a ser das classes-filha
	public abstract void acelerar();

}

public class Carro extends Veiculo {

    public boolean ligado;	

	public Carro() {
		ligado = false;
	}

    public void ligar() {
		ligado = true;
        System.out.println("O veículo ligou!");
    }

    public void desligar() {
		ligado = false;
        System.out.println("O veículo desligou!");
    }

	// Aqui, a classe Carro define como ela deve exercer o ato de acelerar
	@Override
	public void acelerar() {
		if (!ligado){
			throw new Exception("O carro não pode ser acelerado, pois ele está desligado."); // Erro: o carro está desligado!
		}
		System.out.println("O carro foi acelerado");
	}

	public boolean estaLigado() {
		return ligado;
	}
}

public class Bicicleta extends Veiculo {

	// Aqui, a classe Bicicleta define como ela deve exercer o ato de acelerar
	@Override
	public void acelerar() {
		System.out.println("A bicicleta acelerou!");
	}

}

```

Com a utilização da abstração nesse caso, sabemos que qualquer novo tipo de veículo que for criado a partir da classe `Veiculo` terá que obrigatoriamente implementar o comportamento de aceleração. Isso faz muito sentido, já que todo veículo tem que ser capaz de acelerar.

## Polimorfismo

Linguagens orientadas a objetos ainda prevêem o suporte para criação de estruturas polimórficas. Estruturas polimórficas são estruturas que conseguem mudar seu comportamento interno em determinadas circunstâncias. Essa variação comportamental pode acontecer por algumas formas, como através da sobescrita de métodos e através do LSP (*Liskov Substitution Principle*).

No exemplo anterior, nós temos um exemplo de polimorfismo através da sobrescrita de métodos: nós temos a classe `Veiculo`, que possui o método abstrato `acelerar()`. O método é abstrato porque a classe `Veiculo` só sabe que tem que conter este comportamento, mas não sabe como esse comportamento deve ocorrer.

Mas, as classes `Carro` e `Bicicleta` foram obrigadas a implementar o método `acelerar()` por herdarem a classe `Veiculo`. Cada uma dessas classes implementou o método `acelerar()` da maneira mais adequada para cada um dos tipos de veículos. Aqui, já temos um exemplo de polimorfismo: as classes `Carro` e `Bicicleta` são polimórficas, pois possuem um ancestral comum (a classe `Veiculo`) que as obriga a implementar o método `acelerar()`, mas cada uma delas implementa o mesmo método da maneira mais correta para cada tipo de veículo.

Essa mudança de implementação não exigiu a mudança do código da classe `Veiculo`, além de que a implementação dos métodos `acelerar() ` em cada uma das classes é isolada: a implementação do método `acelerar()` na classe `Carro` não afeta a implementação do mesmo método na classe `Bicicleta`, e vice-versa.

Outro exemplo de polimorfismo seria através da aplicação do Princípio da Substituição de Liskov (também conhecido como LSP - *Liskov Substitution Principle*). O LSP é parte de um conjunto de cinco práticas de codificação conhecido como SOLID. Estes princípios visam a produção de código com alta qualidade e alinhado com os princípios das linguagens orientadas a objeto.

Para entender o LSP, considere o código abaixo:

```java
Carro veiculo = new Carro();
// ...
veiculo.acelerar(); // Vai escrever "O carro foi acelerado"
// ...

```

O código não aparenta nada de diferente: temos um objeto chamado `veiculo` do tipo `Carro`. Mas, pelo fato de `Carro` herdar a classe `Veiculo`, nós podemos deduzir que um objeto do tipo `Carro` também pode ser considerado como sendo do tipo `Veiculo`; afinal, todo `Carro` agora é também um `Veiculo` por causa da herança. Sendo assim, podemos escrever o código acima da seguinte maneira:

```java
Veiculo veiculo = new Carro();
// ...
veiculo.acelerar(); // Vai escrever "O carro foi acelerado"
// ...

```

Nós podemos definir o objeto `veiculo` como sendo do tipo `Veiculo`, mas o criar com base em um `Carro`. Nesse momento, o objeto `veiculo` vai se comportar como um `Carro`. No caso acima, dizemos que `Veiculo` é a *abstração*, enquanto `Carro` é a *concretização*. Se quiséssemos trocar o tipo do nosso veículo para uma bicicleta, bastaria trocar a concretização.

Todo o código abaixo continuaria funcionando normalmente, já que uma `Bicicleta` também é um `Veiculo`. Isso torna nosso código muito mais flexível (se quisermos alterar o comportamento do nosso código, basta trocar as concretizaçãoes) e a prova de falhas de escrita de código (já que a abstração vai garantir que o código que vier logo abaixo da definição da concretização vai continuar funcionando de maneira transparente).

```java
Veiculo veiculo = new Bicicleta();
// ...
veiculo.acelerar(); // Vai escrever "A bicicleta foi acelerada"
// ...

```

Neste exemplo, além de todas as vantagens que podemos notar no que diz respeito à qualidade e manutenibilidade do código, podemos dizer que o objeto `veiculo` é um objeto polimórfico, pois a concretização está sendo capaz de alterar seu comportamento. Porém, todo o código subsequente não é afetado por essa troca.

## Conclusão

As definições de classes, objetos, encapsulamento, herança, abstração e polimorfismo constituem os principais pilares do paradigma orientado a objetos. Estes são considerados temas pilares pois, através dele, podemos começar a obter as vantagens que o paradigma orientado a objetos visa oferecer da maneira mais correta possível. É imprescindível que nós, como desenvolvedores, conheçamos estes pilares para que consigamos escrever código orientado a objetos flexível, conciso e com um grau de qualidade superior.

Aqui, vale uma ressalva: cada linguagem oferece estes pilares de uma maneira própria, a depender da filosofia da linguagem. Existem linguagens orientadas a objeto que talvez não ofereçam o conceito de visibilidade de maneira tão explítica; algumas linguagens permitem herança múltipla, outras linguagens oferecem apenas herança simples… De fato, para o total aproveitamento dos conceitos da orientação a objetos, é imprescindível que, além de conhecer estes pilares, o desenvolvedor também conheça a filosofia e a sintaxe da linguagem que está sendo utilizada.

[  ![Desenvolvedor Java](https://d2knvm16wkt3ia.cloudfront.net/assets/svg-icon/java.svg)   Formação Desenvolvedor Java Conhecer a formação ](https://www.treinaweb.com.br/formacao/desenvolvedor-java)

- [ #Orientação a objetos ](https://www.treinaweb.com.br/blog/tag/orientacao-a-objetos)
- [ #Paradigmas ](https://www.treinaweb.com.br/blog/tag/paradigmas)
- [ #OO ](https://www.treinaweb.com.br/blog/tag/oo)

Autor

 ![Cleber Campomori](//secure.gravatar.com/avatar/c659c6a58478cad5b7751370ba94205f?d=mm)

## Cleber Campomori

 Líder de Conteúdo/Inovação. Pós-graduado em Projeto e Desenvolvimento de Aplicações Web. Certificado Microsoft MCSD (Web). 

 [Todos os artigos](https://www.treinaweb.com.br/blog/autor/cleber-campomori)  

## Continue estudando

 Transforme leitura em prática com os cursos e formações da TreinaWeb.

 [Ver cursos](https://www.treinaweb.com.br/cursos)   

  Continue lendo

## Artigos relacionados

- ![](https://dkrn4sk0rn31v.cloudfront.net/uploads/2022/07/DART-ORIENTACAO-OBJETOS-400x280.png)  [ Dart ](https://www.treinaweb.com.br/blog/categoria/dart) 

     4 anos atrás

    ##  [ Orientação a objetos em Dart ](https://www.treinaweb.com.br/blog/orientacao-a-objetos-em-dart) 

     Aprenda Orientação a objetos em Dart e como trabalhar com classes, atributos, métodos e objetos em Dart e aumente seus conhecimentos!

     Ler artigo
- ![](https://dkrn4sk0rn31v.cloudfront.net/uploads/2022/10/o-que-e-e-como-comecar-com-golang-400x280.jpg)  [ Desenvolvimento Back-end ](https://www.treinaweb.com.br/blog/categoria/desenvolvimento-back-end) 

     4 anos atrás

    ##  [ Orientação a objetos na linguagem Go ](https://www.treinaweb.com.br/blog/orientacao-a-objetos-na-linguagem-go) 

     Neste artigo iremos aprender como podemos utilizar a orientação a objetos na linguagem Go, usando structs e pointer receivers.

     Ler artigo
- ![](https://dkrn4sk0rn31v.cloudfront.net/uploads/2022/05/como-instalar-o-csharp-e-nosso-primeiro-exemplo-400x280.png)  [ C# ](https://www.treinaweb.com.br/blog/categoria/csharp) 

     4 anos atrás

    ##  [ Orientação a objetos no C# ](https://www.treinaweb.com.br/blog/orientacao-a-objetos-no-csharp) 

     Aprenda como trabalhar com classes, atributos, métodos e objetos no C# e aumente seus conhecimentos nessa linguagem incrível!

     Ler artigo
- ![](https://dkrn4sk0rn31v.cloudfront.net/uploads/2022/04/PHP-ORIENTACAO-OBJETOS-400x280.png)  [ PHP ](https://www.treinaweb.com.br/blog/categoria/php) 

     5 anos atrás

    ##  [ Orientação a objetos em PHP ](https://www.treinaweb.com.br/blog/orientacao-a-objetos-em-php) 

     Aprenda como trabalhar com classes, atributos, métodos e objetos no PHP e aumente seus conhecimentos nessa linguagem incrível!

     Ler artigo
- ![](https://dkrn4sk0rn31v.cloudfront.net/uploads/2021/02/JAVA-ORIENTACAO-OBJETOS-400x280.png)  [ Java ](https://www.treinaweb.com.br/blog/categoria/java) 

     6 anos atrás

    ##  [ Orientação a objetos em Java ](https://www.treinaweb.com.br/blog/orientacao-a-objetos-em-java) 

     É perceptível a vocação do Java para estruturas orientadas a objetos. Veremos um pouco mais sobre neste artigo.

     Ler artigo
- ![](https://dkrn4sk0rn31v.cloudfront.net/uploads/2022/07/novos-recursos-do-ecmascript-2022-400x280.png)  [ Javascript ](https://www.treinaweb.com.br/blog/categoria/javascript) 

     4 anos atrás

    ##  [ Novos recursos do ECMAScript 2022 ](https://www.treinaweb.com.br/blog/novos-recursos-do-ecmascript-2022) 

     Novos recursos do ECMAScript 2022 que é a décima terceira edição da especificação que vai padronizar tudo no mundo do JavaScript.

     Ler artigo
- ![](https://dkrn4sk0rn31v.cloudfront.net/uploads/2019/10/14112855/O-QUE-É-UML-400x280.png)  [ Tecnologia ](https://www.treinaweb.com.br/blog/categoria/tecnologia) 

     7 anos atrás

    ##  [ O que é UML? ](https://www.treinaweb.com.br/blog/o-que-e-uml) 

     Veja neste artigo o que é UML, qual o seu objetivo e seus principais diagramas.

     Ler artigo
- ![](https://dkrn4sk0rn31v.cloudfront.net/uploads/2021/03/o-que-e-programacao-reativa-400x280.png)  [ Arquitetura de Software ](https://www.treinaweb.com.br/blog/categoria/arquitetura-de-software) 

     6 anos atrás

    ##  [ O que é programação reativa? ](https://www.treinaweb.com.br/blog/o-que-e-programacao-reativa) 

     Confira neste artigo o que vem a ser programação reativa, um princípio de desenvolvimento de software que vem ganhando espaço entre os desenvolvedores.

     Ler artigo
- ![](https://dkrn4sk0rn31v.cloudfront.net/uploads/2020/10/pilares-da-seguranca-da-informacao-400x280.png)  [ Segurança da Informação ](https://www.treinaweb.com.br/blog/categoria/seguranca-da-informacao) 

     6 anos atrás

    ##  [ Pilares da Segurança da Informação ](https://www.treinaweb.com.br/blog/pilares-da-seguranca-da-informacao) 

     As empresas tem se atentado aos pilares da segurança da informação, para garantir a proteção de seus dados. Confira neste artigo quais são esses pilares.

     Ler artigo
- ![](https://dkrn4sk0rn31v.cloudfront.net/uploads/2020/09/importancia-dos-testes-de-software-na-qualidade-do-sistema-400x280.png)  [ Testes e Projetos ](https://www.treinaweb.com.br/blog/categoria/testes-e-projetos) 

     6 anos atrás

    ##  [ Importância dos testes de software na qualidade do sistema ](https://www.treinaweb.com.br/blog/importancia-dos-testes-de-software-na-qualidade-do-sistema) 

     Os testes de software são uma atividade essencial para garantir a qualidade do sistema ou aplicação e não podem ser vistos como algo opcional.

     Ler artigo
- ![](https://dkrn4sk0rn31v.cloudfront.net/uploads/2017/09/big-data-o-que-e-e-qual-a-sua-importancia-400x280.jpg)  [ Tecnologia ](https://www.treinaweb.com.br/blog/categoria/tecnologia) 

     9 anos atrás

    ##  [ Big Data: o que é e qual a sua importância? ](https://www.treinaweb.com.br/blog/big-data-o-que-e-e-qual-a-sua-importancia) 

     Saiba mais sobre o Big Data e como ele pode contribuir com o seu negócio.

     Ler artigo
- ![](https://dkrn4sk0rn31v.cloudfront.net/uploads/2019/03/08160445/capa-linq-400x280.jpg)  [ C# ](https://www.treinaweb.com.br/blog/categoria/csharp) 

     8 anos atrás

    ##  [ Afinal: o que é de fato o LINQ? ](https://www.treinaweb.com.br/blog/afinal-o-que-e-de-fato-o-linq) 

     O LINQ é uma das features mais legais e poderosas do .NET. Porém, você sabe exatamente o que é o LINQ afinal? Sabe como o LINQ trabalha para tornar suas consultas agnósticas? Vamos responder a estas perguntas neste artigo.

     Ler artigo

## Um ano de acesso total para você viver de programação.

 Todos os cursos e formações da TreinaWeb numa única assinatura, com professores que atuam no mercado, suporte direto e certificados. Do primeiro `console.log` ao mercado de trabalho.

- **1 ano** de acesso a **todos os cursos**
- Cursos novos **toda semana**
- Suporte **direto com professores**
- Plano de carreira **personalizado**
- **Certificados digitais** inclusos
- **Aplicativos** para Android e iOS, com **acesso offline**

    **Garantia incondicional de satisfação** 

 Teste por 7 dias e, se não fizer sentido para você, devolvemos seu dinheiro.

### Acesso completo a todos os cursos e dezenas de Formações.

 12 meses 

  Economize R$ 840,00  54% OFF 

 de 12x R$ 129,00 por apenas

 12x  R$ 59,00

 sem juros no cartão de crédito ou R$ 599,00 à vista

  Oferta termina em  **16h 50min 14s**

- Acesso imediato e ilimitado durante 1 ano.
- Plano de carreira personalizado.
- Suporte direto com professores.
- E muito mais!

 [Matricule-se agora](https://www.treinaweb.com.br/checkout/pagamento/plano/anual?cupom=TW-SCLIENTE26)

     [                ](https://www.treinaweb.com.br)

 Escola online de programação, tecnologia e IA.

- [  ](https://www.facebook.com/TreinaWeb/)
- [  ](https://www.instagram.com/treinaweb/)
- [  ](https://www.youtube.com/user/TreinaWeb)
- [  ](https://twitter.com/treinaweb)
- [  ](https://www.linkedin.com/company/treinaweb)
- [  ](https://github.com/treinaweb)

## Inscreva-se em nossa newsletter

Receba lançamentos, promoções e novidades.

   Seu nome     Seu WhatsApp     Seu melhor e-mail   Inscrever-se 

## Cursos

- [ Base para Devs ](https://www.treinaweb.com.br/categoria/base-para-devs)
- [ Front-end ](https://www.treinaweb.com.br/categoria/desenvolvimento-front-end)
- [ Back-end ](https://www.treinaweb.com.br/categoria/desenvolvimento-back-end)
- [ Mobile ](https://www.treinaweb.com.br/categoria/desenvolvimento-mobile)
- [ Bancos de Dados ](https://www.treinaweb.com.br/categoria/bancos-de-dados)
- [ Cloud ](https://www.treinaweb.com.br/categoria/cloud-computing)
- [ IA ](https://www.treinaweb.com.br/categoria/ia)
- [ E mais ](https://www.treinaweb.com.br/categoria/e-mais)
- [ Ver todos os cursos ](https://www.treinaweb.com.br/cursos)

## Conteúdo

- [ Formações ](https://www.treinaweb.com.br/formacoes)
- [ Projetos práticos ](https://www.treinaweb.com.br/projetos-praticos)
- [ Direto ao ponto ](https://www.treinaweb.com.br/direto-ao-ponto)
- [ Planos ](https://www.treinaweb.com.br#assinatura)
- [ Depoimentos ](https://www.treinaweb.com.br#depoimentos)
- [ Comunidade ](https://www.treinaweb.com.br#comunidade)
- [ Corpo docente ](https://www.treinaweb.com.br#docente)

## A empresa

- [ Sobre a TreinaWeb ](https://www.treinaweb.com.br#sobre)
- [ Perguntas frequentes ](https://www.treinaweb.com.br#faq)
- [ Vantagens de estudar na TreinaWeb ](https://www.treinaweb.com.br/vantagens-de-estudar-na-treinaweb)
- [ Cursos para empresas ](https://www.treinaweb.com.br/empresas)
- [ Sugira um novo curso ](https://www.treinaweb.com.br/sugerir-curso)
- [ Trabalhe conosco ](https://www.treinaweb.com.br/trabalhe-conosco)
- [ Artigos ](https://www.treinaweb.com.br/blog)
- [ Desenvolvedores e agentes ](https://www.treinaweb.com.br/developers)
- [ Contato ](https://www.treinaweb.com.br/contato)
- [ Política de privacidade ](https://www.treinaweb.com.br/politica-de-privacidade)
- [ Termos de uso ](https://www.treinaweb.com.br/termos-de-uso)

## Baixe nosso aplicativo

 [   Disponível na **App Store**  ](https://apps.apple.com/us/app/treinaweb/id1322729447) [   Disponível no **Google Play**  ](https://play.google.com/store/apps/details?id=br.com.treinaweb.mobile) 

  Av. Paulista, 1765, Conj 71 e 72 · Bela Vista · São Paulo · SP · 01311-200   © 2004 – 2026 TreinaWeb Tecnologia LTDA · CNPJ 06.156.637/0001-58
