Orientação a Objetos
Este é o material teórico utilizado nas aulas de Orientação a Objetos que eu ministrei aos meus colegas de trabalho. O material original está em slides de Power Point, por isso o conteúdo está basicamente todo em bullet points.
O objetivo do treinamento foi reforçar a compreensão dos fundamentos de Java e dos princípios centrais de POO por meio de aprendizado prático e aplicado.
Você pode encontrar a parte prática (código e exercícios) no post Java & Object-Oriented Programming.
Programação Estruturada (PE)
- Na PE, um programa é composto por três tipos básicos de estruturas:
- sequências: são os comandos a serem executados;
- condições: sequências que só devem ser executadas se uma condição for satisfeita (exemplos:
if-else
,switch
e comandos parecidos); - repetições: sequências que devem ser executadas repetidamente até uma condição for satisfeita (
for
,while
,do-while
, etc.).
- Na PE, um programa é tipicamente escrito em uma única rotina (ou função) podendo, é claro, ser quebrado em sub-rotinas. Mas o fluxo do programa continua o mesmo.
- Além disso, o acesso às variáveis não possui muitas restrições na programação estruturada.
Programação Orientada a Objetos (POO)
- Alternativa à programação estruturada.
- Aproximar o manuseio das estruturas de um programa ao manuseio das coisas do mundo real, daí o nome “objeto” como algo genérico, que pode representar qualquer coisa tangível.
- Esse novo paradigma se baseia principalmente em dois conceitos chave: classes e objetos. Todos os outros conceitos, igualmente importantes, são construídos em cima desses dois.
- Surgida nas décadas de 1960 e 1970.
- Unidade básica da OO é a classe:
- serve de modelo/estrutura para criação de Objetos.
- Componentes básicos utilizados em OO:
- classes
- atributos
- métodos
- objetos
- construtores
Classes
- Molde, estrutura básica do Java.
- Ela contém as instruções para a criação de Objetos.
- Estrutura da classe:
- nome da classe sempre inicia com letra maiúscula, sem caracteres especiais e sem acentos;
- ela tem o mesmo nome do arquivo fonte Java;
- uma classe não possui a implementação do método main;
- tudo que estiver entre as chaves({}) pertence à classe;
- classes não são executáveis;
- toda classe Java possui a forma:
public class NomeDaClasse{}
Atributos
- São as características da classe, propriedades da classe.
- Podemos entendê-los, mas não os tratar como variáveis.
- Também podemos dizer que os atributos são os estados da classe.
- Atributos são nomeados com letras minúsculas, sem caracteres especiais e sem acentos.
Métodos
- Podemos entender os métodos como as ações que a classe disponibiliza para que sejam executadas pelos objetos.
- Podemos dizer que os métodos são os comportamentos da classe.
- A declaração dos métodos deve obedecer os seguintes pontos:
- possuir um tipo de retorno (tipo de dado que o método vai retornar, mesmo que seja vazio);
- nome do método iniciado com um verbo, em letra minúscula, sem caracteres especiais e sem acentuação;
- parâmetros, argumentos de entrada (opcional);
- retorno (opcional) – depende do tipo de retorno.
Objeto
- Classes não realizam ações.
- Classes não criam Objetos (programas criam objetos).
- Objetos são instâncias das classes.
- Formato de trabalho de objetos:
- ClasseX nomeDoObjeto = new ClasseX();
- ClasseX nomeDoObjeto;
- nomeDoObjeto = new ClasseX();
Construtores
- Permitem a instanciação dos objetos da classe.
- Toda classe possui um construtor padrão implícito.
- Construtores podem aceitar parâmetros de entrada:
- Nesse caso o construtor padrão precisa ser explicitamente declarado.
- Construtor é um método especial que não possui retorno.
- Sempre tem o mesmo nome da classe.
- Para o construtor padrão implícito, a JVM (Java Virtual Machine), em tempo de execução, faz a sua declaração automática.
- Para acessar os atributos da classe em um construtor, utiliza-se a instrução this.
- this refere-se sempre à classe atual.
Os 4 pilares da OO
Encapsulamento
Em programação, encapsulamento é “esconder a implementação”, simplificando a interação entre objetos.
Nossa classe pode conter centenas de métodos e implementar comportamentos altamente complexos em várias situações. Mas podemos esconder todos os seus métodos (marcando-os como “privados”), deixando apenas dois ou três métodos de interação com outras classes (marcando-os como “públicos”).
Então todas as outras classes em nosso programa só verão – e chamarão – esses poucos métodos nesta classe.
A melhor maneira de simplificar algo é esconder as coisas complicadas de quem não precisa saber os detalhes sobre elas.
Por exemplo, se você se sentasse atrás dos controles do piloto de um jato Boeing, levaria muito tempo para entender como eles funcionam.
Por outro lado, tudo parece mais simples para os passageiros do avião: eles compram uma passagem e embarcam no avião, que depois decola e aterrissa.
O encapsulamento:
- Restringe o acesso direto aos dados (campos) de uma classe.
- Os campos são definidos como privados.
- Cada campo tem um método getter e setter.
- Métodos getter retornam o campo.
- Os métodos setter nos permitem alterar o valor do campo.
Herança
Em programação, a herança é um relacionamento especial entre duas classes: podemos criar uma classe baseada em outra.
Com isso, podemos fazer o que precisamos usando coisas que já existem.
A nova classe torna-se descendente (herdeira) de uma classe existente.
Isso é super útil quando você já tem uma classe que contém 80-90% dos dados e métodos necessários.
Simplesmente declaramos uma determinada classe como mãe de nossa nova classe. Todos os dados e métodos da classe mãe automaticamente se tornam parte da nova classe.
- Para utilizar a herança, utilizamos a palavra reservada extends.
- Uma classe (filha) pode “estender” outra classe (mãe) herdando suas características.
- Implementa o princípio de programação DRY (Don’t Repeat Yourself).
- Melhora a reutilização do código.
- A herança multinível é permitida em Java (uma classe filha também pode ter sua própria classe filha).
- Heranças múltiplas não são permitidas em Java (uma classe não pode estender mais de uma classe).
Polimorfismo
Em programação, polimorfismo (“muitas formas”) é um conceito que descreve a situação na qual diferentes implementações estão escondidas atrás da mesma coisa.
O polimorfismo nos permite interagir com objetos de diferentes classes (geralmente com um ancestral comum) da mesma maneira.
Para encontrar um análogo na vida real, podemos olhar para o processo de dirigir um carro.
Se uma pessoa pode dirigir um caminhão, ela também pode ser colocada ao volante de uma ambulância ou de um carro esportivo.
Uma pessoa pode dirigir um carro independentemente de seu tipo, porque todos têm os mesmos mecanismos de controle: volante, pedais e câmbio.
Os carros são organizados de maneira diferente por dentro, mas todos compartilham dos mesmos mecanismos.
No polimorfismo:
- O mesmo nome de método é usado várias vezes.
- Diferentes métodos com o mesmo nome podem ser chamados a partir do objeto.
- Todos os objetos Java podem ser considerados polimórficos (no mínimo, são de seu próprio tipo e instâncias da classe Object).
- Overload (sobrecarga de métodos) é um exemplo de polimorfismo estático em Java.
- Override (sobrescrita de métodos) é um exemplo de polimorfismo dinâmico em Java.
Abstração
Serve para dividir algo grande e monolítico em várias partes pequenas.
Em programação, abstração significa dividir um programa em objetos da forma mais adequada possível.
A abstração também permite escolher as principais características de um objeto e omitir as coisas menos importantes.
A abstração pode ser alcançada com classes abstratas ou interfaces.
A palavra reservada abstract é um modificador usado para classes e métodos:
- Classe abstrata: é uma classe restrita que não pode ser usada para criar objetos (para acessá-la, ela deve ser herdada de outra classe).
- Método abstrato: só pode ser usado em uma classe abstrata e não possui corpo. O corpo é fornecido pela subclasse.
Modificadores de acesso
- Os modificadores de acesso em Java especificam a acessibilidade ou escopo de um campo, método, construtor ou classe.
- Podemos alterar o nível de acesso de campos, construtores, métodos e classes aplicando o modificador de acesso nele.
- Existem quatro tipos de modificadores de acesso Java:
- private
- default
- protected
- public
private: O nível de acesso de um modificador “privado” está apenas dentro da classe. Não pode ser acessado de fora da classe.
default: O nível de acesso de um modificador “padrão” está apenas dentro do pacote. Ele não pode ser acessado de fora do pacote. Se você não especificar nenhum nível de acesso, ele será o padrão.
protected: O nível de acesso de um modificador “protegido” está dentro do pacote e fora do pacote por meio da classe filha.
public: O nível de acesso de um modificador “público” está em todos os lugares. Ele pode ser acessado de dentro da classe, fora da classe, dentro do pacote e fora do pacote.
static
- A palavra reservada static em Java é usada principalmente para gerenciamento de memória.
- Podemos aplicar o static a variáveis, métodos, blocos e classes aninhadas.
- O que for modificado com a palavra static passará a ser uma instância da Classe, não do Objeto.
- Atributos e métodos estáticos de um Objeto são compartilhados entre as instâncias.
Variável static
Uma variável estática pode ser usada para se referir a uma propriedade comum a todos os objetos (ou seja, ela não é única para cada objeto).
Exemplo, o nome da empresa dos funcionários, o nome da faculdade dos alunos etc.
Uma variável estática ocupa memória apenas uma vez no tempo de carregamento da classe.
Método static
Um método estático pertence à classe e não ao objeto de uma classe.
Um método estático pode ser invocado sem a necessidade de criar uma instância de uma classe.
Um método estático pode acessar dados estáticos e pode alterar seus valores.
Enums (dados enumerados)
- O Enum em Java é um tipo de dado que contém um conjunto fixo de constantes.
- Por serem constantes, escrevemos em letras maiúsculas.
- Exemplos comuns:
- dias da semana (SEGUNDA-FEIRA, TERÇA-FEIRA, QUARTA-FEIRA, …);
- direções (NORTE, SUL, LESTE, OESTE);
- estações (PRIMAVERA, VERÃO, OUTONO, INVERNO);
- cores (AMARELO, BRANCO, PRETO, AZUL, …);
- Implicitamente os enums são static e final.
Os enums:
- Herdam internamente a classe Enum, portanto, não podem herdar de nenhuma outra classe.
- Podem implementar interfaces.
- Podem ter atributos, construtores, métodos.
- Podem ser facilmente usados em switch.
- Podem ser percorridos.

Precedência de operadores
- A precedência do operadores se estabelece quando duas expressões são vinculadas.
- Em uma expressão, ele determina o agrupamento de operadores com os valores e determina como essa expressão será avaliada.
- Ao resolver uma expressão, deve-se atentar para duas coisas. A primeira é uma precedência e a segunda é a associatividade.
Precedência
- A precedência é a prioridade para agrupar diferentes tipos de operadores com seus operandos.
- Só importa se uma expressão tiver mais de um operador com precedência maior ou menor.
- Os operadores com maior precedência são avaliados primeiro. Se quisermos avaliar primeiro os operadores de menor precedência, devemos agrupar os operandos usando parênteses e depois avaliar.
Associatividade
- Devemos seguir a associatividade se uma expressão tiver mais de dois operadores de mesma precedência.
- Nesse caso, uma expressão pode ser resolvida da esquerda para a direita ou da direita para a esquerda, dependendo do caso.

Tipos primitivos
Os tipos primitivos são tipos de dados especiais internos à linguagem, não sendo objetos criados a partir de uma classe.
Obs.: String não é tipo primitivo, é classe.
Números inteiros

Números de ponto flutuante

As variáveis do tipo double armazenam valores com maior magnitude e precisão do que as do tipo float, e devem ser preferivelmente empregadas quando a precisão do valor for um fator importante.
Caracteres: char
- Permite armazenar um caractere Unicode (utilizando 16 bits).
- Valor mínimo: ‘\u0000’ (ou 0); valor máximo: ‘\uffff’ (ou 65535).
- Valor padrão: ‘\u0000’.
- Representa dados relacionados a texto (letras, símbolos e caracteres especiais).
- String (classe) armazena um conjunto de caracteres.
Valores lógicos: boolean
- Permite armazenar um valor lógico nos estados true ou false (utilizando 1 bit).
- Valor padrão: false.

Casting (conversão de tipo)
A conversão de tipo acontece quando se atribui um valor de um tipo de dado primitivo a outro tipo.
Em Java, existem dois tipos de conversão:
- Widening (expansão).
- Narrowing (restrição).
Widening (expansão): converter automaticamente um tipo menor em um tipo maior:
byte → short → char → int → long → float → doubleNarrowing (restrição): converter manualmente um tipo maior em um tipo menor:
double → float → long → int → char → short → byte
Wrapper Classes
As classes “Wrapper” (“embalar”, “envolver”) nos permite usar tipos primitivos como objetos.
Usamos autoboxing e unboxing para converter automaticamente tipos primitivos em objetos e objetos em primitivos, respectivamente.
São usadas em Collections.

Fontes
Meu artigo sobre como as skins de Counter-Strike: Global Offensive podem nos ajudar a entender POO: Skins de CS:GO e Programação Orientada a Objetos.
Também tem a versão em inglês: CS:GO Skins and Object Oriented Programming.