https://github.com/isaacalves7/java
☕ It's a repository of Java programming language and his content.
https://github.com/isaacalves7/java
android gradle java java-programming javaee javafx jboss jpa jsf jsp junit5 kotlin maven oci oracle-database oracle-db primefaces spring spring-boot
Last synced: 2 months ago
JSON representation
☕ It's a repository of Java programming language and his content.
- Host: GitHub
- URL: https://github.com/isaacalves7/java
- Owner: IsaacAlves7
- Created: 2020-08-27T01:34:11.000Z (almost 6 years ago)
- Default Branch: master
- Last Pushed: 2025-03-22T19:02:14.000Z (about 1 year ago)
- Last Synced: 2025-03-22T20:18:32.113Z (about 1 year ago)
- Topics: android, gradle, java, java-programming, javaee, javafx, jboss, jpa, jsf, jsp, junit5, kotlin, maven, oci, oracle-database, oracle-db, primefaces, spring, spring-boot
- Language: Java
- Homepage:
- Size: 1.17 MB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
> Versículo chave: "Consagre ao Senhor tudo o que você faz, e os seus planos serão bem-sucedidos." - Provérbios 16:3
# It's a repository of Java language ☕
> ☕ **Preparação**: Para este conteúdo, o aluno deverá dispor de um computador com acesso à internet, um web browser com suporte a HTML 5 (Google Chrome, Mozilla Firefox, Microsoft Edge, Safari, Opera etc.), um editor de texto ou IDE (VSCode etc.) e o software JDK, com a versão mais recente, instalado na sua máquina local.

Sou um especialista em desenvolvimento de software com foco no ecossistema Java/Kotlin, atuando com frameworks robustos como Spring Boot, Jakarta EE e Quarkus.
Tenho sólida experiência na aplicação de boas práticas de engenharia de software, como os princípios SOLID, DRY, KISS, TDA e SoC, com domínio na aplicação de design patterns (criacionais, estruturais e comportamentais), além da adoção dos princípios de Clean Code e Clean Architecture para garantir legibilidade, manutenibilidade e escalabilidade do código.
No front-end, colaboro em projetos com SPAs desenvolvidas em React, Angular e Vue, integradas com back-ends Java via APIs REST ou GraphQL. Também participo de aplicações SSR com frameworks como Next.js ou Thymeleaf em projetos fullstack Java. Tenho domínio de HTML/CSS, Flexbox e CSS Grid, com foco em design responsivo baseado em protótipos UI/UX elaborados no Figma.
No back-end, desenvolvo APIs RESTful e GraphQL utilizando Spring Boot (com Spring Web, Spring Data, Spring Security e graphql-java). Tenho experiência com Git e colaboração em times ágeis com pipelines CI/CD (Jenkins, GitLab CI, GitHub Actions), análise estática e linting com ferramentas como Checkstyle, PMD e SonarQube, além da escrita de testes unitários e de integração com JUnit, Mockito, Testcontainers e REST-assured. Trabalho em arquiteturas distribuídas e baseadas em microsserviços com comunicação via REST e mensageria (RabbitMQ, Apache Kafka), com observabilidade garantida por Prometheus, Grafana e logs estruturados com Logback, Logstash ou Elastic Stack.
Também aplico ferramentas de analytics como Google Analytics 4 e Segment, monitorando a usabilidade de componentes e o comportamento dos usuários em ambientes de produção. Tenho experiência com deploy e escalabilidade de aplicações em ambientes PaaS (Heroku, Azure App Service) e uso de recursos em nuvens públicas como AWS (EC2, ECS, RDS, S3), Azure e Google Cloud (App Engine, GKE).
# ☕ The History of Java language

O **Java** é o ambiente computacional, ou plataforma, criada pela empresa estadunidense Sun Microsystems, e vendida para a Oracle depois de alguns anos. A plataforma permite desenvolver programas utilizando a linguagem de programação Java. A tecnologia Java foi desenvolvida na década de 1990, a partir de um projeto pessoal de um funcionário da Sun Microsystems. A ideia inicial estava ligada à criação de uma linguagem de programação que pudesse ser utilizada em diferentes sistemas, alterando o paradigma de que uma aplicação só poderia ser desenvolvida para uso em um único ambiente de hardware e sistema operacional, como era bastante comum na época.
As grandes empresas desenvolviam suas aplicações voltadas para seu ambiente de hardware e software (sistema operacional - SO), e estas aplicações não eram capazes de serem executadas em diferentes plataformas, principalmente de outros fabricantes. Se analisarmos a linguagem C, criada junto com o sistema operacional UNIX, temos uma biblioteca muito vasta de funções, mas poucas são consideradas padrão para atender a diferentes sistemas; e, mesmo assim, uma aplicação compilada em um sistema operacional (ambiente) não pode ser executada em outro.
A linguagem Java rompeu este paradigma e passou a permitir que uma aplicação desenvolvida em um ambiente - hardware + software (SO) - possa ser executada em outro sem necessidade de qualquer outro procedimento. A Sun Microsystems, ao tomar conhecimento desta ideia, deu total apoio ao seu desenvolvimento e criou um grupo com 13 membros, liderado por James Gosling, que passaram a trabalhar exclusivamente neste projeto. A equipe foi batizada de “Green Team” e o grupo passou a trabalhar em um conjunto de escritórios fora das dependências físicas da Sun, e sem qualquer tipo de comunicação com a matriz, durante 18 meses para a concretização desta ideia.
Com a tecnologia Java, as aplicações passaram a ser portáveis de um sistema para o outro, sem nenhuma necessidade de alteração. Por isso, afirmamos que a portabilidade é uma das mais importantes características da linguagem Java.
Ainda naquela época, o grupo já havia antecipado uma nova onda na computação, na convergência entre dispositivos controlados digitalmente e computadores. Hoje em dia, percebemos bem isso quando analisamos um smartphone, um dispositivo digital que possui inúmeras funções de computadores; entre elas, podemos destacar a execução de aplicativos. Inicialmente, a linguagem foi batizada de **Oak**, pois o grupo tinha como vista da janela do escritório *um carvalho*. Posteriormente, a linguagem foi rebatizada como **Java**, em função do *gosto do grupo pelo tipo de café*. Por isso, temos como ícone da linguagem uma xícara de café com sua fumaça característica.
A linguagem é muito poderosa para o desenvolvimento de aplicações, seja para o desenvolvimento de aplicações menos sofisticadas ou para uso em dispositivos menos complexos que computadores, conhecidos como dispositivos inteligentes, tais como cafeteiras, micro-ondas, geladeiras e uma gama de outros dispositivos que possam ser controlados por software. A linguagem ainda é muito eficiente no desenvolvimento de sistemas de entretenimento doméstico, dando suporte a streaming de vídeo e televisão digital, que ainda não era tão desenvolvida na época.

A tecnologia Java permite ainda o desenvolvimento de todos os tipos de aplicações, indo do mais simples controle de um eletrodoméstico, passando por aplicações domésticas, comerciais, de automação, até o desenvolvimento de aplicações mais complexas, com comunicação de dados e aplicações para supercomputadores.
A linguagem Java teve início ao incorporar a tecnologia Java ao navegador de internet *Netscape navigator*, em sua versão de 1995. A tecnologia ganhou a aceitação do mercado e dos desenvolvedores, sendo uma das mais importantes linguagens de programação para o desenvolvimento de sistemas. São dezenas de milhões de desenvolvedores Java no mundo e, atualmente, esta tecnologia é encontrada em supercomputadores, servidores, desktops, notebooks, máquinas de cartões de crédito e débito, robôs, automóveis, jogos eletrônicos, bem como uma gama de dispositivos digitais, redes e demais tecnologias de programação. A linguagem Java ainda é a linguagem nativa para o desenvolvimento de aplicações para o Android (sistema operacional para smartphones).
A tecnologia Java foi totalmente gratuita por muito tempo, mas recentemente a Oracle, que passou a deter os direitos da linguagem após adquirir a Sun Microsystems, está licenciando o uso para empresas com custos. A empresa deve permitir o licenciamento gratuito somente para desenvolvedores avulsos que criam aplicações pessoais sem custo ou para simples aprendizado.
Principais características e vantagens da tecnologia Java:

- Orientada a objetos, com uma grande diversidade de bibliotecas de classes disponível;
- Independe de plataforma: write once, run everywhere ;
- Segurança - Mecanismos para sistemas livres de vírus, pacotes para criptografia;
- Simplicidade;
- Sintaxe dos comandos básicos segue o padrão do C;
- Sintaxe da parte OO bem mais simples que o C++;
- Internacionalização;
- Unicode: padrão que permite manipular textos de qualquer sistema de escrita;
- Robustez;
- Tratamento de exceções;
- JVM (Java Virtual Machine) impede que uma aplicação mal comportada paralise o sistema;
- Distribuída e multitarefa;
- Os programas podem utilizar recursos da rede com a mesma facilidade que acessam arquivos locais;
- Trabalha com diversos protocolos (TCP/IP, HTTP, FTP);
- Execução simultânea de múltiplas threads;
- Gerenciamento de memória;
- Memória virtual gerenciada pela JVM (Java Virtual Machine);
- Garbage collection (limpeza de memória);
- Desempenho;
- Mais rápida que linguagens de script, porém mais lenta que as linguagens compiladas puras;
- Hoje, os problemas de desempenho são resolvidos com compilação just-in-time.


A **plataforma Java** é uma plataforma de software desenvolvida pela Sun Microsystems (agora parte da Oracle), projetada para fornecer um ambiente para o desenvolvimento e execução de aplicações independentes de sistema operacional e hardware, mais especificamente ela é o sistema de implementação do Java. Isso é possível graças ao conceito de *Write Once, Run Anywhere (WORA)*, onde um programa Java pode ser escrito uma vez e executado em qualquer dispositivo que tenha a **Java Virtual Machine (JVM)** instalada. De forma geral, entendemos que plataforma (ambiente de execução) é composta por hardware + software básico (sistema operacional). A plataforma Java é puramente baseada em software, e sua estrutura modular (JVM, API, JRE e JDK) permite que aplicações Java sejam portáveis, seguras e eficientes. Essa arquitetura fez do Java uma das linguagens mais utilizadas no mundo, especialmente em sistemas empresariais, aplicações web e desenvolvimento para dispositivos embarcados.
A plataforma Java é definida apenas em software e possui dois componentes:
- Máquina Virtual Java (JVM - Java Virtual Machine);
- Conjunto de bibliotecas que disponibilizam classes comuns.
Detalhando mais sobre a estrutura da Plataforma Java, ela é composta por quatro camadas principais, cada uma com um papel fundamental:
Máquina Virtual Java (JVM - Java Virtual Machine):
A **JVM** é o coração da plataforma Java e atua como um **interpretador** para o código Java compilado (bytecode). Ela é responsável por:
- Executar programas Java de forma independente do sistema operacional.
- Gerenciar memória automaticamente via **Garbage Collector (GC)**.
- Otimizar o desempenho através da **compilação Just-In-Time (JIT)**.
- Fornecer segurança ao isolar o código executado.
A JVM traduz o **bytecode Java** para instruções específicas da máquina onde está rodando.
Biblioteca de Classes (Java API - Application Programming Interface):
A **API do Java** é um conjunto de bibliotecas padrão que oferece funcionalidades essenciais para o desenvolvimento de aplicações. Ela contém:
- **Pacotes básicos** (`java.lang`, `java.util`, `java.io`) → Manipulação de strings, coleções, entrada/saída, etc.
- **Bibliotecas de rede** (`java.net`) → Comunicação via HTTP, sockets e WebSockets.
- **Bibliotecas de concorrência** (`java.util.concurrent`) → Threads, sincronização, paralelismo.
- **Acesso a bancos de dados** (`java.sql`, `javax.persistence`) → JDBC, JPA.
- **Interface gráfica** (`javax.swing`, `javafx`) → Desenvolvimento de GUIs.
Ambiente de Execução (JRE - Java Runtime Environment):
O **JRE** é o ambiente necessário para executar aplicações Java e contém:
- A **JVM**.
- As **bibliotecas de classes da API Java**.
- Ferramentas básicas para rodar aplicações Java.
Se um usuário final quiser rodar um programa Java, basta ter o **JRE** instalado. No entanto, para desenvolvimento, o JRE sozinho não é suficiente.
Kit de Desenvolvimento Java (JDK - Java Development Kit):

O **JDK** é um **superconjunto do JRE** e inclui ferramentas para **desenvolver** aplicações Java. Ele contém:
- **Compilador (javac)** → Transforma código-fonte Java em **bytecode**.
- **Depuradores e ferramentas de monitoramento** (`jdb`, `jconsole`, `jvisualvm`).
- **Bibliotecas adicionais** para desenvolvimento avançado.
- **Ferramentas para modularização** (desde o Java 9 com `jlink` e `jmod`).
Se um desenvolvedor deseja programar em Java, ele precisa do **JDK**.
Exemplo de Fluxo de Execução na Plataforma Java:
1. Um desenvolvedor escreve um programa em **Java** (`.java`).
2. O código-fonte é compilado pelo **`javac`** e transformado em **bytecode** (`.class`).
3. A **JVM** lê o bytecode e o executa na máquina usando o **JRE**.
API Java:

"Diferentemente das linguagens convencionais, que são compiladas para código nativo, a linguagem Java é compilada para "bytecode" (gerando o .class ou .jar), que é executado por uma máquina virtual Java (JVM - Java Virtual Machine)."
O modelo inicial era interpretado. Já o atual trocou a etapa do interpretador por uma 2ª compilação (compilador JIT, isto é, just-in-time).
A tecnologia Java é composta por três plataformas:

- **J2SE** ou **Java SE (Java Standard Edition)**: base da plataforma, inclui o ambiente de execução e as bibliotecas comuns;
- **J2EE** ou **Java EE (Java Enterprise Edition)**: versão voltada para o desenvolvimento de aplicações corporativas e aplicações web;
- **J2ME** ou **Java ME (Java Micro Edition)**: versão voltada para o desenvolvimento de aplicações móveis ou embarcadas.
A sigla JSE pode referir-se a diferentes tecnologias dependendo do contexto, mas comumente tem dois significados principais:
1. **Java Standard Edition (Java SE)**: Este é um conjunto de especificações e tecnologias fornecidas pela Oracle para o desenvolvimento de aplicativos Java. O Java SE inclui a linguagem de programação Java, a Máquina Virtual Java (JVM) e bibliotecas padrão para criar aplicações de desktop e servidor.
2. **JavaScript Engine**: Este é um motor que executa o código JavaScript, comumente usado em navegadores web para executar scripts em páginas web. Exemplos de motores JavaScript incluem o V8 do Google Chrome, o SpiderMonkey do Mozilla Firefox e o Chakra do Microsoft Edge.
Portanto, a sigla JSE pode se referir tanto ao Java Standard Edition, relacionado à linguagem de programação Java, quanto a um motor JavaScript, relacionado ao JavaScript. O significado exato depende do contexto em que a sigla é utilizada.

## [Java] Ambiente de desenvolvimento

Existem os ambientes JDK e JRE para construir e executar uma aplicação Java.
O **Java Development Kit (JDK)** é uma coleção de programas para, dentre outras tarefas, compilar e executar aplicações Java. Este é o kit necessário para o desenvolvedor, pois contém todo o suporte para a criação de aplicações em Java.
Exemplo:
- Javac (compilador Java);
- Javadoc (utilitário para documentação);
- Java;
- Outros.
Kit com todos os programas necessários para executar aplicações Java. Faz parte do JDK, mas pode ser instalado separadamente para execução em máquinas clientes, uma vez que o JDK é voltado para os desenvolvedores. O JRE pode ser instalado separadamente e dá suporte somente a execução de aplicações ou jogos como o Minecraft, por isso é a versão mais indicada para instalação nas máquinas clientes que apenas executarão aplicações, não sendo responsáveis pelo seu desenvolvimento.

O código de um programa Java é compilado apenas uma vez, gerando um código intermediário, o **bytecode**, que pode ser executado quantas vezes forem necessárias em qualquer ambiente que possua uma máquina virtual Java (JVM) disponível.
Inicialmente a tecnologia Java realizava uma interpretação completa do bytecode, mas atualmente o interpretador realiza uma compilação **just-in-time** (compila o bytecode para o ambiente onde ocorrerá a execução), permitindo aumentar o desempenho da aplicação.
Para o desenvolvimento de aplicações em Java é comum o uso de ferramentas IDEs (Integrated Development Environment), que facilitam a codificação e a realização de testes, sendo as mais conhecidas:
- Eclipse;
- NetBeans;
- IntelliJ;
- BlueJ.
Você pode usar qualquer tipo de ambiente, se preferir um editor de texto como um bloco de notas ou um VSCode você precisa usar a extensão `.java`.
# ☕ [Java] Ambiente de programação

Existem várias ferramentas para o desenvolvimento de sistemas utilizando a linguagem Java, mas os desenvolvedores têm preferência pelos IDEs **Netbeans** e **Eclipse**. Ambos são gratuitos e podem ser adquiridos pela internet através de download.
É importante que você já tenha instalado o JDK antes de instalar o seu IDE escolhido (Netbeans ou Eclipse). Assista o vídeo:
Existem dois arquivos diferentes: o primeiro, com o source, contém os códigos fonte no Netbeans e não é o ideal para trabalharmos o desenvolvimento. A versão adequada para nós é a versão bin, que contém todos os códigos já compilados e prontos para a execução e desenvolvimento de projetos e aplicações Java.
Você não precisa instalar as duas, pois ambas são concorrentes e desempenham as mesmas funcionalidades. A preferência é a critério do programador.
A linguagem Java possui uma base de construção semelhante à linguagem C e, por isso, boa parte de sua estrutura e sintaxe se assemelha a ela. Desta forma, programadores com conhecimento nesta linguagem tem grande facilidade com a sintaxe da linguagem Java. Outra importante semelhança está nas estruturas de controle de fluxo, que são construídas da mesma forma em ambas as linguagens.
> Cuidado com as diferenças de versões no sistema operacional: se instalar o Java para 64 bits, você deverá usar um IDE (Netbeans ou Eclipse) de 64 bits. O mesmo para a versão de 32 bits: tanto o Java quanto o IDE deverão ser para 32 bits.
## [Java] `Hello, World!`
Veja abaixo o passo a passo para criar sua primeira aplicação em Java, imprimindo na tela o `Hello, World!`, você pode usar qualquer editor de texto e salvar a extensão do arquivo `.java`, mas nesse exemplo, eu estarei utilizando a IDE Netbeans:
O projeto `Exemplo` foi criado e automaticamente teremos uma **classe inicial** para execução da aplicação.

O ambiente está pronto para digitarmos o código da aplicação: preencha o código conforme o exemplo a seguir.

[](#)
```java
import java.util.Scanner;
public class Exemplo {
// identação do bloco da classe Exemplo (a classe sempre possui o nome do arquivo, os dois andam bem alinhados!)
public static void main(String[] args) {
// identação do bloco do método main
// TODO Auto-generated method stub
Scanner sc = new Scanner(System.in);
double media, nota1, nota2;
System.out.println("Digite a nota 1:");
nota1 = Double.parseDouble(sc.nextLine());
System.out.println("Digite a nota 2:");
nota2 = Double.parseDouble(sc.nextLine());
media = (nota1 + nota2) /2.0;
System.out.println("A sua média é:" + media);
sc.close();
} // encerramento da identação do bloco do método main
} // encerramento da identação da classe Exemplo
```
Após o código estar pronto e sem erros, podemos executar a aplicação clicando sobre o “arquivo da classe” com o botão direito, e em seguida clicar sobre a opção `Run file`.

A aplicação executará na parte inferior do Netbeans:

Crie um programa em java e execute os seguintes comandos para abri-lo como saída pelo terminal:
[](#)
```java
public class HelloWorld {
public static void main(String[] args)
{
System.out.println("Hello, World!");
}
}
```
Configurando a saída do programa pela interface de linha de comando (CLI) do terminal:
```sh
# Compilar o App na JVM
javac app.java
java app
# Compilar o arquivo .JAR na JVM
java -jar app.jar
# Compilar o arquivo .JAR na JVM pelo Powershell usando versão específica
& "C:\Program Files\Java\jre1.8.0_471\bin\java.exe" -jar app.jar --installServer
```
A linguagem **Java** tem boa parte de suas características herdadas da linguagem **C**. Muitos dos seus operadores, formação de identificadores, comandos de controle de fluxo e várias outras características são compartilhados entre estas duas linguagens.
Todas as instruções da linguagem Java devem terminar por um símbolo de ponto e vírgula “;”. Você não usará o ponto e vírgula quando a instrução for uma codificação que irá continuar com um bloco de comandos.
Vejamos um exemplo:
```java
System.out.println(“Mensagem do sistema”);
```
Os blocos de comandos em Java são delimitados por { (abrir) e } (fechar) chaves, em que a instrução anterior define que todos os comandos do bloco farão parte desta. Isso irá ocorrer em classes, métodos e instruções de controle de fluxo.
Exemplo:
```java
if(nota>10.0) {
System.out.println(“Nota inválida”);
}
```
Como usar a endentação? Quando desenvolvemos um programa em qualquer linguagem, é comum que utilizemos um conjunto de espaços na frente das instruções de forma a facilitar a visualização de blocos. Sempre que iniciamos um bloco, devemos começar na próxima linha com um deslocamento de pelo menos quatro espaços em brando ou uma tabulação (normalmente quatro espaços). Isso permite que identifiquemos rapidamente que certo conjunto de instruções faz parte de um conjunto que será executado em bloco.
Exemplo:
```java
import java.util.Scanner;
public class Exemplo {
// identação do bloco da classe Exemplo (a classe sempre possui o nome do arquivo, os dois andam bem alinhados!)
public static void main(String[] args) {
// identação do bloco do método main
// TODO Auto-generated method stub
Scanner sc = new Scanner(System.in);
double media, nota1, nota2;
System.out.println("Digite a nota 1:");
nota1 = Double.parseDouble(sc.nextLine());
System.out.println("Digite a nota 2:");
nota2 = Double.parseDouble(sc.nextLine());
media = (nota1 + nota2) /2.0;
System.out.println("A sua média é:" + media);
sc.close();
} // encerramento da identação do bloco do método main
} // encerramento da identação da classe Exemplo
```
Em todas as linguagens de programação, devemos identificar variáveis, programas, funções, métodos, parâmetros etc. O ato de nomear algo em uma linguagem de programação é uma forma de identificação da linguagem. Em Java são permitidos identificadores que comecem com letras (maiúsculas ou minúsculas), ou um símbolo de “$” (dólar) ou “_” (underscore /underline). Números podem ser usados, mas não para iniciar um identificador.
**Java** é uma linguagem de programação sensível à caixa (alta ou baixa ou **case sensitive**). Desta forma, a linguagem faz distinção entre letras maiúsculas e minúsculas. Mas isso não quer dizer que podemos utilizar qualquer nome como um identificador, pois existem algumas palavras reservadas que não podem ser utilizadas para tal.
Exemplos de identificadores válidos em Java:

- `identificador`
- `nomeCompleto`
- `NomeCompleto`
- `nota1`
- `_sys_path`
- `$user`
Observe que os exemplos 2 e 3 possuem a mesma grafia, mas, como existe mudança entre caixa alta e baixa, para a linguagem Java são dois diferentes identificadores.
Palavras reservadas da linguagem Java (não podem ser usadas como identificadores), dentre elas podemos destacar:
abstract
arguments
await
boolean
break
byte
case
catch
char
class
const
continue
debugger
default
delete
do
double
else
enum
eval
export
extends
false
final
finally
float
for
function
goto
implements
if
import
in
instanceof
int
interface
let
long
native
new
null
package
private
protected
public
return
short
static
super
switch
synchronized
this
throw
throws
tdrow
transient - true
try
typeof
var
void
volatile
while
with
yield
> OBS: Todas as palavras reservadas começam por letras minúsculas e são palavras do idioma inglês.
## [Java] Comentários
O uso de comentários em Java é semelhante ao usado na linguagem C, mas apenas dois destes tipos são iguais nas duas linguagens, sendo o terceiro tipo somente disponibilizado na linguagem Java.
Vejamos:
// comentário de uma linha
Quando usamos duas barras em uma linha de código, todo o seu conteúdo, após as duas barras, é desconsiderado pelo compilador, o que quer dizer que podemos escrever qualquer conteúdo que o mesmo não será compilado. É muito usado para deixar informações e avisos do programador no código.
```java
// TODO Auto-generated method stub
```
/**/ comentário de duas ou mais linhas (bloco)
Ao usarmos o comentário de bloco, podemos comentar não apenas um trecho de uma linha, mas todo um conjunto de linhas. É utilizado quando temos longos trechos de textos com avisos e informações, ou para a depuração do código. Para a depuração do código, podemos comentar um conjunto de linhas para realizar um conjunto de testes. Neste caso, podemos comentar um conjunto de instruções ou porque estas instruções estão com problemas e queremos verificar as demais. Ou, ao contrário, onde temos um conjunto de instruções já testadas e corretas e queremos apenas testar as demais. Seja como for, o uso do comentário de bloco é muito usual e comum entre os programadores.
/***/ comentário de documentação
O comentário de documentação se difere do comentário de bloco por possuir um asterisco a mais no início, mas ambos encerram da mesma forma. Existe uma ferramenta na linguagem Java responsável por extrair de um projeto (com várias classes) todos os comentários de documentação e montar um documento com todo este conteúdo.
Neste caso, usamos este tipo de comentário apenas para descrever avisos e informações das classes, de forma a realizar a documentação do sistema ainda durante sua fase de criação. Isto permite que o desenvolvedor descreva todo a documentação no próprio projeto, facilitando a descrição e a manutenção do sistema. Assim, ao terminar um projeto ou realizar algum tipo de modificação, basta gerar novamente a documentação do sistema que tudo estará atualizado.
# ☕ [Java] Tipos de dados
A linguagem Java possui nove tipos de dados básicos, sendo oito deles primitivos e um tipo especial. Os **tipos primitivos** (armazenam apenas valores) são os tipos básicos de variáveis que armazenam valores simples, sem a necessidade de objetos ou referências. São fundamentais para armazenar valores simples e são divididos em oito categorias:
**Tipo lógico** (`boolean`), o tipo lógico só permite dois estados, verdadeiro (true) ou falso (false); em Java ainda é permitido o uso de on e off, ou yes e no.
Exemplo:
```java
boolean status = true;
```
**Tipo caractere** (`char`), o tipo `char` permite que seja armazenado na memória apenas um caractere e se difere do texto (`String`) por ser definido entre `‘e’`. Quando usamos aspas simples ou dupla determinamos apenas um caractere.
Exemplo:
```java
char letra = ‘A’;
```
Também é possível armazenar caracteres de controle:
Caractere Especial
Representação
’\n’
nova linha.
’\r’
enter.
’\u????’
especifica um caractere Unicode o qual é representado na forma Hexadecimal.
’\t’
tabulação.
’\\’
representa um caractere \ (barra invertida).
’\” ’
representa um caractere “ (aspas)
> OBS: A barra invertida na frente indica que é um caractere especial.
**Tipos inteiros** (`byte`, `short`, `int` e `long`), são quatro diferentes tipos de inteiros, que se diferenciam pela quantidade de bits que cada um ocupa em memória para armazenar um valor. Isto faz com que, quanto menor a quantidade de bits, maior seja a limitação do valor a ser armazenado. Entretanto, em ocasiões onde a memória é pouca, devemos trabalhar muito bem com estas diferenças para reduzir o espaço de memória necessário. O uso mais comum é do int, mas, para números muito grandes ou muito pequenos, devemos usar o long. Já para economizar memória podemos usar byte ou short, de acordo com o valor que será armazenado.
Tipo de dado
Quantidade de bits
Quantidade de Bytes
Escopo (valores que podem ser armazenados)
byte
8
1
-2⁷ . . . . 2⁷ - 1
short
16
4
-2³¹ . . . . 2³¹ - 1
long
64
8
-2⁶³ . . . . 2⁶³ - 1
**Tipos reais** (`float` e `double`) são dois diferentes tipos de valores reais, sendo um de precisão simples (float), que ocupa menos espaço de memória, e o de dupla precisão, que ocupa mais memória. Quanto maior o número de bits para armazenar um valor real, maior será a precisão deste número dentro do sistema. O uso do float é comum quando necessitamos economizar espaço de memória. Em Java, todo tipo de dado numérico é convertido para double automaticamente por coerção (força a conversão de tipo). Por isso, é mais indicado, quando não houver falta de espaço de memória, a utilização de double para armazenamento de valores reais.
Tipo de dado
Quantidade de bits
Quantidade de Bytes
float
32
4
double
64
8
**Tipo especial** pode se referir a estruturas que vão além dos tipos primitivos e de referência comuns. Alguns exemplos incluem, `Enum` (enumeração) que define um conjunto fixo de constantes nomeadas:
```java
enum DiaDaSemana { SEGUNDA, TERÇA, QUARTA, QUINTA, SEXTA, SÁBADO, DOMINGO }
```
**Tipo texto** (String) não é um tipo primitivo, mas um tipo especial. Na verdade, o tipo String é uma classe e por isso começa com letra maiúscula, ao contrário dos tipos primitivos, que sempre começam por minúsculas. Este tipo de dado armazena um conjunto de caracteres, formando palavras ou frases de tamanhos variados. Como classe, veremos mais tarde que elementos do tipo String possuem métodos que podem realizar ações específicas sobre o seu conteúdo.
Exemplo:
```java
String nome = “João da Silva”;
```
# ☕ [Java] Constantes e variáveis
**Variáveis** e **constantes** em Java devem obrigatoriamente possuir um tipo. Isso ocorre porque Java é uma linguagem de programação fortemente tipada. Linguagens de programação fortemente tipadas Obrigam que todas as variáveis e constantes sejam definidas por um tipo de dado.
Linguagens de programação fracamente tipadas permitem que variáveis sejam usadas a qualquer momento, sem a necessidade de terem um tipo predefinido. Isso quer dizer que o tipo de dado pode variar em diferentes partes do programa.
**Variáveis** são declaradas por meio de um tipo e um identificador, sem que sejam necessárias outras informações. A boa prática em programação Java determina que todas as variáveis comecem por letras minúsculas e, somente se tiver mais de uma palavra, o inicial da segunda palavra em diante deverá começar por letras maiúsculas.
Exemplos:
```java
int c;
double nota1 = 0; // indica que a variável será inicializada com 0 (zero)
String nomeCompleto;
```
A definição de constantes precisam do modificador final, que indica que, uma vez que ocorreu uma atribuição a variável, seu conteúdo não poderá ser mudado. Em Java, constantes podem ser criadas em nomes em minúsculas ou maiúsculas, mas a boa prática de programação determina que sua identificação deve ser toda em maiúsculas.
Exemplos:
```java
final int IDADEMINIMA = 15;
final double VALORDOLAR = 3.96;
final NOMEEMPRESA = “Super Empreendimentos”;
```
# ☕ [Java] Operadores e expressões
Operador
Descrição
=
Atribuição
+
Soma
-
Subtração
*
Multiplicação
/
Divisão
%
Resto da divisão
**Operadores aritméticos** em Java são usados para realizar operações matemáticas básicas entre valores numéricos. Eles incluem:
> OBS: Java sempre realizará a operação inteira quando os operandos forem inteiros, e a operação real ocorrerá caso um ou mais operando seja real.
Exemplos:
```java
// o valor atribuído será 3 e não 3.5, porque ambos os operandos são inteiros
int v = 7 / 2;
// o valor atribuído será 3.5, porque o primeiro operando é real.
double v = 7.0 / 2;
```
A mesma lógica serve para variáveis:
```java
int a, b=7, c=2;
a = b / c; // será armazenado 3 em a.
double a, b=7.0, c=2.0;
a = b / c; // será armazenado 3.5 em a.
```
Podemos alterar o tipo de um operando em uma expressão utilizando o **cast**, que nada mais é do que informar que o valor armazenado na variável terá o seu valor em função do tipo alterado.
Exemplo:
```java
int b=7, c=2;
double a=0;
a = (double) b / c; // o valor de b será convertido para double antes da operação
// e isso fará com que o primeiro operando seja real e desta
// forma a operação será real, armazenado 3.5 em a.
```
```java
+= -= *= /= %=
```
Exemplo:
```java
int alturaParede = 2.85; // declaração da variável alturaParede
alturaParede += 0.15; // a variável alturaParede terá o valor
// acrescido (somado) em 0.15, sendo
// equivalente a:
// alturaParede = alturaParede + 0.15;
```
Desta forma, não precisamos colocar o nome da variável duas vezes.
Em Java temos os operadores de incremento ++ e de decremento --, que sempre adicionam uma unidade (++) ou subtraem uma unidade (--). Eles podem ser ainda divididos em **pré-incremento** e **pós-incremento**, e **pré-decremento** e **pós-decremento**.
O **pré-incremento** determina que primeiro seja realizada a operação de incremento e depois é realizada a operação de atribuição.
Exemplo:
```java
int a = 20, b=0;
b = ++a; // primeiro a variável a será incrementada de uma unidade, valendo 21,
// depois b receberá o valor de a e assim, também valerá 21.
```
O **pós-incremento** determina que antes seja realizada a atribuição para só então ser realizada a operação de incremento.
Exemplo:
```java
int a = 20, b=0;
b = a++; // primeiro b receberá o valor de a, que é 20 (antes do incremento),
// depois a será incrementado e assim, o valor de a será 21 e o de b será 20.
```
O **pré-decremento** determina que primeiro seja realizada a operação de decremento e depois é realizada a operação de atribuição.
Exemplo:
```java
int a = 20, b=0;
b = --a; // primeiro a variável a será decrementada de uma unidade, valendo 19,
// depois b receberá o valor de a e assim, também valerá 19.
```
O **pós-decremento** determina que antes seja realizada a atribuição para só então ser realizada a operação de decremento.
Exemplo:
```java
int a = 20, b=0;
b = a--; // primeiro b receberá o valor de a, que é 20 (antes do incremento),
// depois a será decrementado e, assim, o valor de a será 19 e o de b será 20.
```
**Operadores de Relacionais** são usados para definir condições.
Operador
Descrição
==
Igualdade/ Comparação
!=
Negação/ Diferente
>
Maior que
<
Menor que
>=
Maior ou igual a
<=
Menor ou igual a
Exemplos:
```java
/*1)*/ if(a > b) { ... }
/*2)*/ while (a <=100) { ... }
/*3)*/ for (int c =0; c<50; c++) { ... }
```
Operadores de em Expressões Lógicas
Operador
Descrição
!
NÃO lógico
&&
E lógico
||
OU lógico
São os determinantes das tabelas-verdade.
Ordem de precedência: `!, &&, ||`
Exemplos:
```java
if(a > b && c < d) { ... }
while (a <=100 || b == 10) { ... }
if( !a == 15 && b >= 10) { ... }
if( !a == 15 || c > d && b >= 10) { ... }
```
Pela ordem de precedência: `if( (!a == 15) || (c > d && b >= 10))`
Primeiro será executada a negação (`!`); depois o e lógico (`&&`) e por último o ou lógico (`||`).
Operadores de bits
Operador
Descrição
&
E entre bits
^
OU EXCLUSIVO entre bits
|
OU entre bits
Ordem de precedência:
&
^
|
# ☕ [Java] Estruturas de programação
Comandos de controle de fluxo Servem para determinar se as condições são verdadeiras ou controlar uma determinada ordem lógica de eventos para o código.
## [Java] Estrutura condicional
Se (`if`):
```java
if (condição) {
// instruções;
}
// A cláusula else é opcional.
```
`if ... else`:
```java
if (condição) {
// instruções;
}
else {
// instruções;
}
```
`if ... else if ... else`
```java
if (condição1) {
instruções;
}
else if (condição2) {
instruções;
}
else if (condição3) {
instruções;
}
else {
instruções;
}
```
> A cláusula `if` deve ocorrer apenas uma vez; As cláusulas `else if` podem ocorrer: nenhuma, uma ou várias vezes; A cláusula `else` só pode ocorrer uma única vez.
switch … case
Estruturas de decisão caracterizadas pela possibilidade de uma variável possuir vários valores diferentes em uma determinada situação.
Uma única estrutura switch pode analisar vários diferentes valores para a variável de controle. A variável de controle em Java pode ser do tipo: inteiro, caractere, ou String.
A cláusula case pode ocorrer de uma a várias vezes, e a cláusula default é opcional.
https://medium.com/javarevisited/re-write-this-java-if-else-code-block-or-ill-reject-your-pull-request-953f20c0f544
## [Java] Estrutura de Laços de Repetição (Loops)
`for` é uma estrutura de repetição (Laços de repetição ou Loop) controlada por uma ou mais variáveis contadoras e caracterizada pela existência de três parâmetros, sendo todos eles opcionais:
**1** - Inicialização da(s) variável(is) de controle
**2** - Condição sobre a(s) variável(is) de controle para parada das iterações
**3** - Passo da(s) variável(is) de controle a cada iteração
```java
for((1)inicialização; (2)condição de controle; (3)passo) {
// instruções
}
```
Exemplo:
1) Repetição controlada por uma variável:
```java
for (int c=1; c<=limite; i++) {
instruções;
}
```
2) Repetição controlada por duas variáveis:
```java
for (a=1, b=2; a*b<limite; a++, b+=2) {
instruções;
}
```
3) Repetição sem fim
```java
for ( ; ; ) {
instruções;
}
```
`while`, esta estrutura realiza a repetição de um conjunto de instruções enquanto a condição determinada for verdadeira; caso a condição seja falsa no primeiro teste, nenhuma instrução será executada.
```java
// realiza o teste da condição no início da estrutura
while (condição) {
instruções;
}
```
`do...while` esta estrutura de repetição é semelhante à anterior, mas com o diferencial de que as condições devem ser verificadas apenas no final da estrutura, obrigando que as instruções sejam sempre executadas pelo menos uma vez.
```java
// Teste de condição no final
do
{
instruções;
} while (condição);
```
# ☕ [Java] Entrada e Saída de dados
Em Java temos muitas formas de **entrada de dados** (input), inclusive de forma gráfica. Inicialmente trabalharemos com a *classe* Scanner, responsável pela entrada de dados em formato texto, com perguntas diretas ao usuário e a inclusão da resposta em variáveis do programa.
Para realizarmos esta tarefa, é necessário que seja criado um objeto da classe `Scanner`.
Para isso, devemos **importar** a *classe* Scanner antes do início da programação da classe:
```java
import java.util.Scanner;
```
Depois é necessário criar o **objeto** para realizar as entradas de dados:
```java
public class EntradaDados {
public static void main (String[] args) {
Scanner entrada = new Scanner(System.in);
}
}
```
Existem vários métodos associados a classe `Scanner` para a entrada de dados, mas para evitarmos problemas futuros podemos usar sempre a entrada de dados de texto (nextLine()) e converter o texto para o tipo desejado.
Exemplo:
1) Para entrada de texto (String):
```java
String nome;
Nome = entrada.nextLine(); // não precisa de conversão, apenas da entrada.
```
2) Para entrada de valor real:
```java
double nota1;
nota1=Double.parseDouble(entrada.nextLine());
// a entrada de dados em texto precisa de conversão para double.
```
3) Para entrada de valor inteiro:
```java
int idade;
idade = Integer.parseInt(entrada.nextLine());
// a entrada de dados em texto precisa de conversão para int
```
É aconselhável evitar o uso de métodos como:
- `entrada.nextDouble();`
- `entrada.nextFloat();`
- `entrada.nextInt();`
Estes métodos, quando usados em conjunto, podem fazer com que a aplicação pule alguma entrada de dados, sendo necessário que seja realizada uma “limpeza de buffer”. Este tipo de problema pode ser contornado ao usar sempre o método “`nextLine()`” e a conversão de tipos.
A **saída de dados** (output) em modo texto pode ser realizada pela *classe* System, e o método out.print (não pula linha), out.println (pula linha) ou outros métodos:
1) Apenas uma mensagem:
```java
System.out.println("Entre com a Nota A1.........: ");
```
2) Mensagem e conteúdo de variáveis:
```java
System.out.println(" Nome: " + nome + " Idade: " + idade + " Nota 1: " + nota1);
```
A seguir temos o exemplo completo de um programa que recebe duas notas e apresenta a média.
```java
public class Exemplo {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc = new Scanner(System.in);
double media, nota1, nota2;
System.out.println("Digite a nota 1:");
nota1 = Double.parseDouble(sc.nextLine());
System.out.println("Digite a nota 2:");
nota2 = Double.parseDouble(sc.nextLine());
media = (nota1 + nota2) /2.0;
System.out.println("A sua média é:" + media);
sc.close();
}
}
```
## [Java] Conversão de tipos
A conversão de tipos em Java pode ser feita por cast ou com o uso de conversão por classes. Ambos já foram vistos em exemplos anteriores:
1) Por cast: Usado para converter valores de um tipo para outro; com cast basta indicar o tipo que você quer que a variável, ou valor, seja convertida, colocando o tipo desejado entre parênteses:
2) Por uso de classes para conversão de textos em valores:
```java
double nota1 = Double.parseDouble(“7.8”);
int idade = Integer.parseInt(“34”);
float valor = Float.parseFloat(“2.15”);
long valor2 = Long.parseLong(“3456789”);
Pode-se usar ainda:
Byte.parseByte() / Short.parseShort()
```
# ♨️ [Java] A boa prática em programação Java

A boa prática em programação Java leva em conta um conjunto de regras que facilitam o desenvolvimento de aplicações e melhoram bastante o trabalho em conjunto realizado por equipes. Ao seguir estas regras, projetos podem ser desenvolvidos em paralelo por diferentes programadores, sem que seja necessário que cada componente precise esperar que outros terminem suas tarefas. Estas regras foram utilizadas na construção da linguagem permitindo que não seja necessário decorar as sintaxes de instruções Java. Não são obrigatórias, mas permitem a codificação melhor de nossas aplicações. Vamos ver algumas dessas regras na prática:
1 - Variáveis auxiliares, atributos, métodos e objetos devem ser identificados iniciando por letras minúsculas. Quando houver mais de uma palavra, deve-se começar cada nova palavra com uma letra maiúscula.
Exemplos:
```java
int idade;
int maiorIdade;
String nome;
String nomeCompleto;
```
2 - Constantes devem ser identificadas por letras maiúsculas em todo o seu nome; mesmo quando temos mais de uma palavra, todo o identificador deve ficar em maiúsculas.
Exemplos:
```java
final int idade;
final int maiorIdade;
final String nome;
final String nomeCompleto;
```
3 - Classes e interfaces (tipo especial de classe) devem iniciar por letras maiúsculas. Quando houver mais de uma palavra, deve-se começar cada nova palavra com uma letra maiúscula.
Exemplos:
```java
public class Carro { ... }
public class Carro Hibrido { ... }
public interface Basico { ... }
public interface MetodosBasicos { ... }
```
4 - Técnicas Básicas de Economia de Memória para Programação em Java: Melhores Práticas para Otimizar Código Java e Reduzir o Uso de Memória. Java é uma linguagem de programação popular amplamente utilizada para desenvolver aplicações complexas. No entanto, um dos problemas comuns dos programas Java é o alto uso de memória, que pode levar a problemas de desempenho e até mesmo travamentos. Portanto, é importante usar técnicas de economia de memória para otimizar o código Java e reduzir o uso de memória.
Uso de tipos de dados primitivos: Ao usar tipos de dados primitivos em vez de seus wrappers de objetos, podemos economizar memória evitando a sobrecarga da criação de objetos.
```java
int x = 42; // use int instead of Integer
double d = 3.14; // use double instead of Double
boolean b = true; // use boolean instead of Boolean
```
Evite a criação desnecessária de objetos:
```java
String s = "Hello" + " World"; // use StringBuilder instead
```
Essa linha de código cria um objeto de `new string` para a `string` concatenada `"Hello World"`. Em vez disso, podemos usar um `StringBuilder` para anexar as strings e evitar criar um novo objeto para cada concatenação:
```java
StringBuilder sb = new StringBuilder();
sb.append("Hello");
sb.append(" World");
```
# ☕ [Java] Classes e objetos

A **programação orientada a objetos (OOP)** tem como principal conceito representar, em um sistema computacional, um objeto da vida real. Esta representação deve descrever o objeto quanto às suas características e ações que poderá realizar dentro do sistema. Não devemos nos preocupar com todas as características presentes no objeto, mas com aquelas que serão necessárias ao sistema (requisitos).
Exemplo: A placa de um automóvel é importante para um sistema de estacionamento, assim como a hora de chegada e saída.
Em alguns casos, o `fabricante`, `modelo` e a `cor` do automóvel poderão ser importantes, mas dificilmente iremos cadastrar o número do `chassi` do mesmo. Como o número do `chassi` não é facilmente visto e seu cadastramento dependeria da documentação do automóvel ou de uma análise para a identificação, que seria difícil, uma vez que é um identificador com muitas letras e números, acabaria por gerar filas e insatisfação dos clientes.
Entretanto, para o sistema de cadastramento do `DETRAN`, por exemplo, o número do `chassi` é uma das informações mais importantes. Dessa forma, identificarmos a `placa` é importante como descritor do automóvel para o sistema de estacionamento, já o `chassi` não.
Por isso, devemos analisar cada objeto separadamente e quais são as características importantes para o sistema em que o objeto será utilizado. Como outro exemplo, podemos notar que a `matrícula`, `nome` e `CR` de um `aluno` são importantes para o sistema acadêmico, mas o time para o qual o `aluno` torce ou sua religião não são. Por isso, os descritores time e religião não são importantes para o objeto `Aluno` em um sistema acadêmico.
As **classes** Java são responsáveis pelo **conjunto de códigos para a criação de objetos e aplicações**. Uma classe Java deve descrever as *características e ações* que o objeto possui ao ser representado em um sistema computacional, levando em consideração as caracteristicas (atributos) e as ações (métodos) juntamente ou não com seus argumentos (parâmetros).
**Atributo** é conceitualmente um descritor do objeto e deve representar uma **característica**, dele. O **conjunto de atributos** do objeto deve representar todas as *características importantes* do objeto para o sistema.
Exemplo:
```java
String matricula; // atributo para armazenamento da matrícula
String nome; // atributo para armazenamento do nome
double cr; // atributo para armazenamento do cr
```
**Método** é uma **ação**, um conjunto de instruções a serem executadas por um objeto para realizar uma determinada tarefa.
O **conjunto de métodos** de um objeto deve descrever **todas as ações (tarefas ou funções)** que o objeto poderá realizar dentro do sistema.
Exemplo:
```java
public int soma(int n1, int n2){
int soma;
soma = n1 + n2;
return soma;
}
public void imprimeAumento(double salario, int percentual){
double aumento;
aumento = salario + salario * percentual / 100.0;
System.out.println("O salário com aumento é: " + aumento);
}
```
A classe modela o **objeto** de acordo com as necessidades do sistema para a sua descrição e suas ações. A partir de uma mesma classe, vários objetos diferentes, mas com características semelhantes, podem ser criados em um mesmo sistema ou em diferentes sistemas.
Se consideramos a classe Aluno, podemos criar a partir desta classe dezenas, centenas ou mesmo milhares de objetos Alunos com características semelhantes, tais como matrícula, nome e CR, mas com propriedades (valores próprios nos atributos de cada objeto) diferentes.
Os *objetos* só existem durante a execução do sistema, pois estes só existirão como referência na memória do computador neste momento. Dizemos também que os objetos só existem “em tempo de execução”, uma vez que o sistema ao ser encerrado terá toda a sua memória apagada. Consequentemente, todas as suas variáveis e objetos não existirão mais.
Exemplo: `Aluno.java` (objeto com o nome da classe)
```java
// Classe Aluno
public class Aluno { // declaração e início da classe
// Atributos devem ser identificados começando por letras minúsculas
String matricula, nome;
double cr;
// Métodos devem ser identificados começando por letras minúsculas
public void imprimir() {
System.out.println("Matrícula: " + matricula);
System.out.println("Nome: " + nome);
System.out.println("CR: " + cr);
}
} // termino da classe
```
# ☕ [Java] Aplicações Java

**Aplicações em Java** são classes especiais que possuem um método main(). O método `main` é responsável por criar os objetos e realizar a combinação de diferentes classes para atender às necessidades de um sistema.
Em cada sistema, temos apenas uma aplicação, que será responsável pela lógica de criação e uso das classes. A comunicação entre os objetos ocorre por meio de trocas de mensagens, que são expressas com o uso de métodos. Uma aplicação, então, cria objetos a partir de uma ou mais classes e usa os métodos dos objetos para realizar as ações que atenderão às necessidades dos usuários.
Exemplo: `AppAluno.java` (aplicação)
```java
// Aplicação para uso da Classe Aluno
public class AppAluno { // Declaração e início da classe
public static void main(String[] args){ // Método inicial da App
Aluno aluno1 = new Aluno();
Aluno aluno2 = new Aluno();
Aluno aluno3 = new Aluno();
// Definindo valores para os atributos do aluno1
aluno1.matricula = "1001";
aluno1.nome = "André";
aluno1.cr = 6.7;
// Definindo valores para os atributos do aluno2
aluno2.matricula = "1002";
aluno2.nome = "Maria";
aluno2.cr = 7.5;
// Definindo valores para os atributos do aluno3
aluno3.matricula = "1003";
aluno3.nome = "João";
aluno3.cr = 7.0;
// Exibindo os valores dos atributos de cada aluno
aluno1.imprimir();
aluno2.imprimir();
aluno3.imprimir();
}
}
```
> [!Note]
> 1. Cada classe pública (`public`) deve ser criada em um arquivo próprio e o nome da classe deve ser o mesmo do arquivo. Ou seja, a classe Aluno deve ser criada no **arquivo** Aluno.java e a **classe da aplicação** "`AppAluno`" deve ser criada no arquivo AppAluno.java. No projeto, seja no Eclipse ou no Netbeans, deverão ser criadas duas classes, uma para o `Aluno` e outra para a aplicação;
>
> 2. Foi criada apenas uma classe `Aluno`, mas a partir dela poderemos criar quantos objetos quisermos;
>
> 3. Na aplicação foram criados três diferentes objetos do tipo `Aluno`. Isso faz com que cada **objeto** `Aluno` (`aluno1`, `aluno2` e `aluno3`) seja criado na memória em locais diferentes (endereços) e possuam espaço de alocação de memória diferentes para cada atributo de cada objeto;
4. Cada *objeto* criado é independente do outro e possui valores próprios para os seus atributos (propriedades). Como a ação é realizada pelo objeto, cada método fará a ação sobre os atributos do objeto indicado, evitando que haja qualquer tipo de alteração indevida nos valores de cada um.

5. Operador new serve para criar um novo objeto e instancia-lo com (), portanto, é um método construtor.
```java
nome_da_classe nome_do_objeto = new método_construtor();
```
A classe `Aluno` passou a ser uma **biblioteca de classes**, e esta classe pode ser reutilizada em diversas outras aplicações. Esse conceito é um dos mais importantes na programação orientada a objetos, pois reduz o trabalho. Qualquer classe criada poderá ser reaproveitada inúmeras vezes por diversas aplicações, poupando esforço de desenvolvimento e facilitando a manutenção.
Cada classe criada se torna uma parte da sua biblioteca de classes e, conforme você vai criando novas classes, a sua biblioteca tende a aumentar. Dessa forma, quando você for criar novas aplicações, terá à sua disposição uma séria de classes já prontas e disponíveis para reaproveitar, sem precisar de novas.
Se você precisar realizar qualquer melhoria em uma classe da sua biblioteca, você poderá realizar sem problemas, pois qualquer inclusão não afetará o uso desta classe nas aplicações antigas, mantendo a compatibilidade entre todas as aplicações.
Com base no reaproveitamento de código da programação orientada a objetos, podemos realizar alterações de melhoria, atualização ou qualquer manutenção em uma classe. Isso fará com que todas as aplicações sejam atualizadas quando forem recompiladas.
# ☕ [Java] Métodos Getters e Setters

Por questões de segurança e falta de controle, não é comum realizar acessos diretos aos atributos de um objeto, por isso são criados métodos específicos para receber o valor e realizar a **atribuição (Setters)**, ou para a **recuperação (Getters)** de um valor armazenado nos atributos de um objeto. Este processo pode evitar que valores incorretos sejam atribuídos sem qualquer chance de análise.
**Métodos Setters** são métodos especiais que recebem o valor do atributo e, por serem métodos, podem analisar se são válidos, sendo responsáveis pela atribuição. Quando o atributo é protegido (privado), é necessário um método para realizar a atribuição.
Características dos métodos Setters:
- São sempre do tipo void, pois métodos Setters não devem retornar nada;
- Devem ser públicos para que a aplicação tenha acesso ao método;
- Devem começar pela palavra set e o nome do atributo: como tem mais de uma palavra, cada nova palavra no nome deve começar por letra maiúscula;
- Possui sempre um parâmetro do mesmo tipo do atributo que receberá o valor, pois ambos (parâmetro e atributo) devem ser do mesmo tipo.
A verificação do valor a ser atribuído não pode ser realizada quando efetuamos uma atribuição direta:
```java
Aluno a = new Aluno();
a.cr = -5.0;
```
O uso de um método Setter neste caso evitará que seja atribuído um valor inválido para o CR, no caso `-5.0`;
Exemplo: `Aluno.java` Setter = `Aluno.class`
```java
// Classe Aluno
public class Aluno { // Declaração e início da classe
// Atributos devem ser identificados começando por letras minúsculas
String matricula, nome;
double cr;
// Métodos devem ser identificados começando por letras minúsculas
public void imprimir() { // Método imprimir(os dados do Aluno)
System.out.println("Matrícula: " + matricula);
System.out.println("Nome: " + nome);
System.out.println("CR: " + cr);
}
// Setter
public void setCr(double c){
if(c >= 0.0 && c <= 10.0){
cr = c;
}
}
}
```
Exemplo: `AppAluno.java` (aplicação chamando o Setter) - `AppAluno.class`
```java
// Aplicação para uso da Classe Aluno
public class AppAluno { // Declaração e início da classe
public static void main(String[] args){ // Método inicial da App
Aluno aluno1 = new Aluno();
Aluno aluno2 = new Aluno();
Aluno aluno3 = new Aluno();
Aluno a = new Aluno();
// Definindo valores para os atributos do aluno1
aluno1.matricula = "1001";
aluno1.nome = "André";
aluno1.cr = 6.7;
// Definindo valores para os atributos do aluno2
aluno2.matricula = "1002";
aluno2.nome = "Maria";
aluno2.cr = 7.5;
// Definindo valores para os atributos do aluno3
aluno3.matricula = "1003";
aluno3.nome = "João";
aluno3.cr = 7.0;
a.cr = -5.0;
// Exibindo os valores dos atributos de cada aluno
aluno1.imprimir();
aluno2.imprimir();
aluno3.imprimir();
a.setCr(-5.0); // setter
}
}
```
- Note que o parâmetro c recebe o valor a ser atribuído ao CR (`-5.0`), mas antes de atribuir é realizada uma verificação do valor para averiguar se o mesmo é válido. No caso, o valor do parâmetro é menor do que zero.
- Como sabemos que um CR não pode ser negativo, a atribuição não será realizada, assim como a tentativa de realizar a atribuição de um CR maior do que `10` (dez) também não permitirá que a atribuição ocorra.
Apenas atribuições com valores válidos poderão ser realizadas neste caso.
O **Métodos Getters** são métodos especiais que retornam o valor armazenado no atributo, evitando acesso direto a ele pela aplicação. Assim como visto no método Setter, a proteção do atributo (`private`) fará com que a aplicação não tenha acesso direto a ele, fazendo com que seja necessário um método público para recuperar o valor atribuído ao mesmo.
Características dos métodos Getters:
- São sempre do mesmo tipo do atributo que será retornado, nunca do tipo void;
- Devem ser públicos para que a aplicação tenha acesso ao método;
- Devem começar pela palavra get e o nome do atributo: como tem mais de uma palavra, cada nova palavra no nome deve começar por letra maiúscula;
- Não possui parâmetro: esses métodos nunca receberão parâmetros, uma vez que não farão atribuições ou ações com parâmetros, realizando apenas o retorno do valor armazenado no atributo.
Exemplo: `Aluno.java` Getter
```java
// Classe Aluno
public class Aluno { // Declaração e início da classe
// Atributos devem ser identificados começando por letras minúsculas
String matricula, nome;
double cr;
// Métodos devem ser identificados começando por letras minúsculas
public void imprimir() { // Método imprimir(os dados do Aluno)
System.out.println("Matrícula: " + matricula);
System.out.println("Nome: " + nome);
System.out.println("CR: " + cr);
}
// Setter
public void setCr(double c){
if(c >= 0.0 && c <= 10.0){
cr = c;
}
}
// Getter
public double getCr() {
return cr;
}
}
```
Note que não existe parâmetro, o método apenas deve retornar o valor armazenado e por isso não pode ser void, sendo o tipo de retorno do mesmo tipo do atributo que será retornado, e a ação é a de retorno (`return`).
No futuro, os atributos das nossas classes serão protegidos contra acesso direto (privado), impedindo que a aplicação possa acessar diretamente um atributo. Dessa forma, é necessário que usemos os métodos *Setters* e *Getters* para atribuir e recuperar os valores do atributo.
Exemplo: `Aluno.java` (versão com métodos Setters e Getters.)
```java
public class Aluno {
// Atributos devem ser identificados começando por letras minúsculas
String matricula, nome;
double cr;
// Métodos também
public void setMatricula(String m){
if(!m.isEmpty()) { // se o parâmetro m NÃO (!) estiver vazio
matricula = m; // será feita a atribuição
}
}
public String getMatricula() {
return matricula; // retorna a matricula
}
public void setNome(String n){
if(!n.isEmpty()){ // se o parâmetro n NÃO (!) estiver vazio
nome = n; // será feita a atribuição
}
}
public String getNome(){
return nome; // retorna o nome
}
public void setCr(double c){
if(c >= 0 && c <= 10) {
cr = c;
}
}
public double getCr() {
return cr; // retorna o CR
}
public void imprimir() { // Método imprimir(os dados do Aluno)
// Os Getters usados aqui!
System.out.println("Matrícula: " + getMatricula());
System.out.println("Nome: " + getNome());
System.out.println("CR: " + getCr());
}
}
```
Exemplo: `AppAluno.java` (nova versão)
```java
// Aplicação para o uso da Classe Aluno
public class Aluno {
public static void main(String[] args) {
Aluno aluno1 = new Aluno(); // Criação da nova instância do objeto aluno1 (instanciação)
Aluno aluno2 = new Aluno(); // Criação da nova instância do objeto aluno2 (instanciação)
Aluno aluno3 = new Aluno(); // Criação da nova instância do objeto aluno3 (instanciação)
// Definindo valores para os atributos do aluno1
aluno1.setMatricula("1001");
aluno1.setNome("André");
aluno1.setCr(6.7);
// Definindo valores para os atributos do aluno2
aluno2.setMatricula("1002");
aluno2.setNome("Isaac");
aluno2.setCr(7.7);
// Definindo valores para os atributos do aluno3
// Valores vazios e inválidos, não serão atribuídos
aluno3.setMatricula("");
aluno3.setNome("");
aluno3.setCr(12);
// Exibição dos valores dos atributos de cada aluno
aluno1.imprimir();
aluno2.imprimir();
aluno3.imprimir();
}
}
```
> [!Note]
>
> 1. Os valores dos atributos dos alunos `1` e `2` serão atribuídos normalmente, mas os valores do `aluno3` não, porque a `matrícula` e o `nome` estão vazios e o `CR` não é válido;
>
> 2. Os valores foram atribuídos utilizando os métodos Setters, que verificaram se os valores eram válidos para só então realizar as atribuições;
>
> 3. Os métodos Getters foram usados na própria classe `Aluno` para buscar os valores armazenados nos atributos do objeto no método `imprimir`.
Exemplo: A classe `Carro` possui os atributos e métodos a seguir, crie a classe `Carro` e a aplicação `AppCarro`, realize a entrada de dados na aplicação através do teclado, e ao final imprima os dados dos respectivos carros (através do método imprimir()).
Classe `Carro`:
Atributos
Métodos
Fabricante: texto
- Setters para todos os atributos
Modelo: texto
- Getters para todos os atributos
Cor: texto
- Imprimir() // imprime todos os atributos
Placa: texto
Valor: real
Número de Portas: inteiro
Ano de fabricação: inteiro
Ano do Modelo: inteiro
`Carro.java`
```java
public class Carro {
// Attributes
String fabricante, modelo, cor, placa;
double valor;
int numeroPortas, anoFabricacao, anoModelo;
// Setter methods
public void setFabricante (String fab){
if(!fab.isEmpty()) {
fabricante = fab;
}
}
public void setModelo (String mad){
if(!mod.isEmpty()) {
modelo = mod;
}
}
public void setCor (String c){
if(!c.isEmpty()) {
cor = c;
}
}
public void setPlaca (String p){
if(!p.isEmpty()) {
placa = p;
}
}
public void setValor (String val){
if(!val.isEmpty()) {
valor = val;
}
}
}
```
`AppCarro.java`
```java
import java.util.Scanner;
// Scanner para imprimir os dados
public class AppCarro {
public static void main (String[] args){
Scanner entrada = new Scanner(System.in);
Carro car1 = new Carro();
// Entrada de Dados
System.out.println("---------- Entrada de Dados - Carro ----------");
// Fabricante
System.out.println("Digite o Fabricante do Carro: ");
car1.setFabricante(entrada.nextLine());
// Modelo
System.out.println("Digite o Modelo do Carro: ");
car1.setModelo(entrada.nextLine());
// Placa
System.out.println("Digite a Placa do Carro: ");
car1.setPlaca(entrada.nextLine());
// Cor
System.out.println("Digite a Cor do Carro: ");
car1.setCor(entrada.nextLine());
// Valor
System.out.println("Digite o Valor do Carro: ");
car1.setValor(Double.parseDouble(entrada.nextLine()));
// Número de Portas
System.out.println("Digite o Nº de Portas do Carro: ");
car1.setNumeroPortas(Integer.parseInt(entrada.nextLine()));
// Ano de Fabricação
System.out.println("Digite o Ano de Fabricação do Carro: ");
car1.setAnoFabricacao(Integer.parseInt(entrada.nextLine()));
// Ano do Modelo
System.out.println("Digite o Ano do Modelo do Carro: ");
car1.setAnoModelo(Integer.parseInt(entrada.nextLine()));
// Saída de Dados
System.out.println("--------------- Saída de Dados - Carro ---------------");
car1.imprimir();
}
}
```
> [!Note]
> Você pode ver que temos algumas repetições de código para realizar a entrada de dados de cada objeto. Se aumentarmos o número de objetos, aumentaremos consideravelmente o tamanho do código. Para resolver este problema e evitarmos a redundância de códigos, vamos incluir um novo método na classe `Carro`, um método para a entrada de dados. Desta forma, evitamos a redundância dos códigos de entrada de dados.
Classe `Carro`
Atributos
Métodos
Fabricante: texto
- Setters para todos os atributos
Modelo: texto
- Getters para todos os atributos
Cor: texto
Imprimir() // imprime todos os dados do carro
Placa: texto
- EntradaDados () // realiza a entrada de dados do carro
Valor: real
Valor: real
NumeroPortas: inteiro
AnoFabricacao: inteiro
AnoModelo: inteiro
Nova solução do exercício prático, com a inclusão do método `entradaDados` na classe `Carro`:
`Carro.java`
```java
import java.util.Scanner;
public class Carro {
// Usando regras de boas práticas em Java
// Para identificadores da classe, dos atributos e dos métodos
String fabricante, modelo, cor, placa;
double valor;
int numeroPortas, anoFabricacao, anoModelo;
// Getters e Setters Fabricante
public String getFabricante(){
return fabricante;
}
}
```
`AppCarro.java`
```java
public class AppCarro {
public static void main (String[] args){
// TODO Auto-generated method stub
Carro car1 = new Carro();
car1.entradaDados();
car1.imprimir();
Carro car2 = new Carro();
car2.entradaDados();
car2.imprimir();
Carro car3 = new Carro();
car3.entradaDados();
car3.imprimir();
}
}
```
> [!Note]
> Você pode perceber agora que existe um método para a entrada de dados na classe `Carro`, e que ele está sendo usado por cada carro para realizar a entrada de dados pelo teclado, evitando que os códigos das entradas de dados fiquem redundantes.
> Além disso, a aplicação ficou muito mais simples. Caso você tenha vários objetos carros, você não terá redundância, portanto sua aplicação ficará mais simples.
> Faça um teste executando a nova aplicação e analise o resultado. Inclua mais dois objetos carros e teste novamente: você verá que a aplicação terá uma pequena mudança, mas a classe Carro ficará inalterada.
> A partir deste momento, todas as classes deverão sempre conter o método entradaDados().
## [Java] Métodos construtores

A programação orientada a objetos permite que possamos controlar a criação de um objeto através dos chamados **métodos construtores**. Tal característica permite que um método especial, o método construtor, seja executado no momento em que ocorre a criação do objeto (objeto é instanciado) e um conjunto de ações (instruções) podem ser programadas para serem realizadas neste momento.
Entre essas ações, pode-se destacar o recebimento de dados iniciais para serem atribuídos e/ou preparar o objeto para que este esteja apto a atender às necessidades para qual foi criado.
Um método construtor pode ainda ser usado para determinar o tamanho de um vetor que será usado pelo objeto, assim como *pré-configurar estruturas de dados de suporte* ao objeto que está sendo criado.
São métodos especiais executados apenas uma vez por cada *objeto* criado, pois somente são executados no momento da **instanciação / criação do objeto**, sendo responsáveis por realizar as ações necessárias para a sua criação (controlar a criação do objeto).
Características dos métodos construtores:
1. São sempre públicos (`public`, característica de encapsulamento – veremos mais adiante), não podendo ter nenhum tipo de restrição;
2. Não existe definição de tipo de retorno, pois métodos construtores não podem retornar valores com a instrução “`return`”, são sem tipo;
3. Devem ser identificados sempre com o mesmo nome da classe;
4. São executados exclusivamente durante o processo de criação / instanciação do objeto, não podendo ser usados pelo objeto após a sua criação.
`Pessoa.java`
```java
public class Pessoa {
// Attributes
String nome, identidade;
int idade;
// Constructor method
public Pessoa(String nome, String identidade, int idade) {
// Setters e Attributes
setNome(nome);
setIdentidade(identidade);
setIdade(idade);
}
// Getters and Setters - Nome
public String getNome(){
return nome;
}
public void setNome(String no) {
if(!no.isEmpty()) {
nome = no;
}
}
// Getters and Setters - Identidade
public String getIdentidade(){
return identidade;
}
public void setIdentidade(String iden) {
if(!iden.isEmpty()) {
identidade = iden;
}
}
// Getters and Setters - Idade
public String getIdade(){
return identidade;
}
public void setIdade(String ida) {
if(ida > 0) {
idade = ida;
}
}
// Método imprimir()
public void imprimir() {
System.out.println("Pessoa: " + nome);
System.out.println("RG: " + identidade);
System.out.println("Idade: " + idade);
}
}
```
`AppPessoa.java`
```java
public class AppPessoa {
public static void main(String[] args) {
Pessoa p1 = new Pessoa("Isaac", "7", 24);
p1.imprimir();
}
}
```
1. Na classe `Pessoa`, o método construtor:
```java
public Pessoa(String nome, String identidade, int idade)
```
O método é público, não possui tipo de retorno antes no nome identificador do método, seu identificador é igual ao nome da classe, por isso começou por letra maiúscula e só será usado para criar o objeto (instanciar);
2. A partir do momento em que um método construtor é criado, a classe só poderá ser instanciada se usarmos um método construtor existente. Por isso, o objeto Pessoa p1 não pode ser criado e sua criação foi comentada na aplicação, pois este método tenta utilizar um método construtor que não existe na classe;
3. O objeto `p2` usa um método construtor existente e por isso pode ser criado;
4. Com o uso do método construtor, os dados recebidos como parâmetros puderam ser utilizados para realizar as atribuições nos atributos do objeto, determinando os valores de suas propriedades no momento da criação do objeto;
5. Os métodos `setIdentidade` (`String id`) e `setIdade` (`int id`) podem ter o mesmo identificador para o parâmetro porque o parâmetro `id` é declarado em diferentes métodos e, sendo assim, ele é válido internamente em cada um dos métodos separadamente.
O processo de compilação de uma classe cria um método construtor vazio quando não for encontrado nenhum método construtor. Desta forma, nos exemplos anteriores, as classes `Aluno` e `Carro` não tinham métodos construtores, então o compilador criou respectivamente os métodos a seguir para as classes `Aluno` e `Carro`:
```java
public Aluno ( ) { }
// e
public Carro ( ) { }
```
Quando não temos um construtor em uma classe, um construtor VAZIO é criado no processo de compilação.
# ☕ [Java] Polimorfismo

**Polimorfismo** quer dizer muitas formas. O **polimorfismo de sobrecarga** permite o emprego de operadores e identificadores de várias formas, sendo então necessária uma contextualização para que seja realizada a operação adequada. Este contexto está ligado ao emprego do operador, método etc., de acordo com uma situação.
Polimorfismo de sobrecarga de operadores:
```java
int b=5, c=3;
int a = b + c;
// o símbolo de + neste contexto está realizando uma operação
// de soma entre valores inteiros, no caso b + c (inteiros)
double x=3.5, y=2.2;
// temos um novo contexto, pois a operação será realizada entre dois valores reais, no caso x+y
double z = x + y;
```
A mudança de contexto faz com que as operações a serem realizadas sejam diferentes, pois toda linguagem de programação possui diferentes formas de realizar as operações de soma inteira e real. Desta forma, a expressão aritmética a seguir utiliza as duas operações conjuntamente:
```java
double z = ( 2 + 5) / (3.5 + 1.5);
```
Na primeira operação de soma, os operandos são inteiros, então a operação a ser realizada será de uma soma inteira, para somente depois ser realizada a operação de soma real. Desta forma, teremos em um instante a seguinte situação:
```java
double z = ( 7) / (5.0);
```
Assim, a operação de divisão será real e não inteira porque existe um operando real.
Em Java, todas as operações aritméticas serão realizadas em função dos tipos dos operandos, e a operação será inteira apenas se ambos os operandos foram inteiros. Caso contrário (um operando inteiro e outro real ou dois operandos reais), a operação será real.
O operador + é um dos mais usados, sendo um bom exemplo de **sobrecarga de operadores**, pois pode ser utilizado de várias e diferentes formas em função do contexto:
1. Concatenação: String nome = "João" + " da " + "Silva";
2. Soma inteira: int a = 3 + 4;
3. Soma real: double b = 1.3 + 2.7;
4. Incremento: x++; ou ++x;
5. Concatenação entre textos e valores: System.out.println("Idade" + p2.getIdade());
Agora imagine a seguinte instrução:
```java
System.out.println("Valor =" + (( 3 + 4) + (1.3 + 2.7) + (++x)));
```
A *sobrecarga de operadores* está sendo usada de diferentes formas em uma mesma instrução. Cada contexto será avaliado para que seja executada a operação adequada em cada caso.
Toda expressão é avaliada sintaticamente, assim como cada contexto será avaliado individualmente no momento da execução.
O **Polimorfismo de sobrecarga de métodos** permite que possamos ter mais de um método com o mesmo identificador em uma mesma classe. Isso só é possível em razão da avaliação do contexto no momento da execução. Vamos levar em consideração que eu desejo realizar o cálculo da área de um quadrado e de um retângulo em uma mesma classe.
Para realizar o cálculo da área do quadrado, eu preciso apenas do valor da base do quadrado. Assim, o método área ficaria da seguinte forma:
```java
public int area (int base){
return ((int) Math.pow(base,2)); // Math.Pow calcula a base elevada a 2
}
```
Já para realizar o cálculo da área do retângulo, eu preciso do valor da base e da altura do quadrado. Assim, o método área ficaria da seguinte forma:
```java
public int area(int base, int altura){
return(base * altura);
}
```
## [Java] Assinaturas

Esses dois métodos podem conviver na mesma classe, uma vez que eles possuem diferentes *assinaturas*. A **assinatura de um método** é determinada pelo tipo de parâmetros e pela ordem em que estes foram declarados. Desta forma, a assinatura do primeiro método é:
```java
area ( int );
```
e do segundo:
```java
area ( int , int );
```
Diante da diferença de assinaturas, podemos ter dois diferentes contextos para o uso do método de cálculo da área:
```java
System.out.println("Área = " + area( 5 ));
```
1. No primeiro contexto, é chamado para executar o método área com um único parâmetro e neste caso a avaliação em tempo de execução irá determinar que deve ser usado o cálculo da área do quadrado. Ou seja, aquele que recebe um valor inteiro como parâmetro, e a resposta será: 25.
```java
System.out.println("Área = " + area( 5, 6 ));
```
2. No segundo contexto, é chamado para executar o método área com um dos parâmetros e, neste caso, a avaliação em tempo de execução irá determinar que deve ser usado o cálculo da área do retângulo. Ou seja, aquele que recebe dois valores inteiros como parâmetro, e a resposta será: 30.
> [!Warning]
> Com o uso da sobrecarga de métodos você poderá criar quantos métodos com o mesmo identificador (nome) quiser em uma mesma classe, desde que eles **não possuam a mesma assinatura de método**.
## [Java] Métodos

Se quisesse incluir um método para calcular a área de uma circunferência, você não poderia incluir nesta classe, pois ele teria a mesma assinatura do método do cálculo da área do quadrado:
```java
public static int area(int raio) {
return ((int) Math.PI * Math.pow(raio,2));
// Math.Pow calcula o raio elevado a 2
}
```
O método teria a mesma assinatura do método área do quadrado e, no momento da execução, não haveria como saber qual dos dois deveria seria executado, pois ambos teriam o mesmo contexto:
```java
System.out.println("Área Quadrado = " + area( 5 ));
System.out.println("Área Circunferência = " + area( 4 ));
```
A linguagem Java não teria como definir qual método executar, já que ambos têm a mesma assinatura e a linguagem não é suficientemente inteligente para tentar buscar isso em algum outro lugar que não o contexto da chamada do método:
```java
area( 5 )
// e
area( 4 )
```
Como ambos possuem o mesmo contexto, os métodos com a mesma assinatura não podem compartilhar a mesma classe.
Exemplos de polimorfismo de sobrecarga válidos para uma mesma classe:
```java
meuMetodo(int a, double b, String c){
return 1;
}
meuMetodo(double b, String c, int a){
return 2;
}
meuMetodo(String c, int a, double b){
return 3;
}
meuMetodo(String c, double b, int a){
return 4;
}
```
As assinaturas são respectivamente:
```java
meuMetodo(int, double, String)
meuMetodo(double, String, int)
meuMetodo(String, int, double)
meuMetodo(String, double, int)
```
Todos os métodos acima, apesar de possuírem a mesma quantidade de parâmetros, têm assinaturas diferentes que serão executadas em função de contexto diferentes, respectivamente:
```java
int g = meuMetodo(2, 2.25, "Casa");
int h = meuMetodo(2.25, "Casa", 2);
int i = meuMetodo("Casa", 2, 2.25);
int j = meuMetodo("Casa", 2.25, 2);
```
Os valores armazenados em `g`, `h`, `i` e `j` serão respectivamente: `1, 2, 3 e 4`.
## [Java] A sobrecarga de métodos construtores

**Métodos construtores** são métodos e também podem ser sobrecarregados. Uma classe que possui mais de um método construtor é uma classe que oferece diferentes formas de criação para os seus objetos.
Outra forma de uso de *mais de um construtor* é para manter a compatibilidade de uma classe com suas aplicações antigas.
Se analisarmos a classe Carro, vista como exemplo anteriormente, podemos notar que ela não possui nenhum método construtor. Podemos então criar alguns métodos construtores para esta classe e preservar a aplicação antiga, criando e analisando uma classe nova (evoluída) e as duas aplicações, a antiga e a nova:
Classe: `Carro` (atualizada com cinco métodos construtores)
```java
import java.util.Scanner;
public class Carro{
// Use as regras da boa prática em programação Java
// para os identificadores da classes, dos atributos e dos métodos
// Atributos
String fabricante, modelo, cor, placa;
double valor;
int numeroPortas, anoFabricacao, anoModelo;
// Construtor Methods
public Carro() { }
public Carro(String placa, double valor){
this.placa = placa;
this.valor = valor;
}
public Carro(String madelo, String cor, String placa, double valor){
this.modelo = modelo;
this.cor = cor;
this.placa = placa;
this.valor = valor;
}
public Carro(String fabricante, String madelo, String cor, String placa, double valor){
this.fabricante = fabricante;
this.modelo = modelo;
this.cor = cor;
this.placa = placa;
this.valor = valor;
}
public Carro(String fabricante, String madelo, String cor, String placa, double valor,
int numeroPortas, int anoFabricacao, int anoModelo){
this.fabricante = fabricante;
this.modelo = modelo;
this.cor = cor;
this.placa = placa;
this.valor = valor;
this.numeroPortas = numeroPortas;
this.anoFabricacao = anoFabricacao;
this.anoModelo = anoModelo;
}
// Getters and Setters Methods
// Fabricante - Getters and Setters
public String getFabricante() {
return fabricante;
}
public void setFabricante (String fab){
if(!fab.isEmpty()) {
fabricante = fab;
}
}
// Modelo - Getters and Setters
public String getModelo() {
return modelo;
}
public void setModelo (String mad) {
if(!mod.isEmpty()) {
modelo = mod;
}
}
// Cor - Getters and Setters
public String getCor() {
return cor;
}
public void setCor (String co) {
if(!co.isEmpty()) {
cor = co;
}
}
// Placa - Getters and Setters
public String getPlaca() {
return placa;
}
public void setPlaca (String pla){
if(!pla.isEmpty()){
placa = pla;
}
}
// Valor - Getters and Setters
public double getValor(){
return valor;
}
public void setValor(double val){
if(val > 0){
valor = val;
}
}
// Número de Portas - Getters and Setters
public int getNumeroPortas(){
return numeroPortas;
}
public void setNumeroPortas (int nportas){
if(nportas > 0){
numeroPortas = nportas;
}
}
// Ano de Fabricação - Getters and Setters
public int getAnoFabricacao(){
return anoFabricacao;
}
public void setAnoFabricacao(int anofab){
if(anofab > 0){
anoFabricacao = anofab;
}
}
// Ano de Modelo - Getters and Setters
public int getAnoModelo(){
return anoModelo;
}
public void setAnoModelo(int anomod){
anoModelo = anomod;
}
public void imprimir(){
System.out.println("Fabricante : " + getFabricante() );
System.out.println("Modelo : " + getModelo() );
System.out.println("Cor : " + getCor() );
System.out.println("Placa : " + getPlaca() );
System.out.println("Valor : " + getValor() );
System.out.println("Número de Portas : " + getNumeroPortas() );
System.out.println("Ano de Fabricação : " + getAnoFabricacao() );
System.out.println("Ano do Modelo : " + getAnoModelo() );
}
public void entradaDados(){
Scanner entrada = new Scanner(System.in);
// o objeto Scanner deve ficar local aos métodos
// o objetivo do Scanner para entrada de dados em um atributo do carro
// vamos utilizar o objeto para entrada de dados
System.out.println("Digite o Fabricante do carro :");
setFabricante( entrada.nextLine() );
System.out.println("Digite o Modelo do carro :");
setModelo( entrada.nextLine() );
System.out.println("Digite a Cor do carro :");
setCor( entrada.nextLine() );
System.out.println("Digite a Placa do carro :");
setPlaca( entrada.nextLine() );
System.out.println("Digite o Valor do carro :");
setValor( Double.parseDouble( entrada.nextLine() ));
System.out.println("Digite o Número de Portas do carro :");
setNumeroPortas( Integer.parseInt( entrada.nextLine() ));
System.out.println("Digite o Ano de fabricação do carro :");
setAnoFabricacao( Integer.parseInt( entrada.nextLine() ));
System.out.println("Digite o Ano do Modelo do carro :");
setAnoModelo( Integer.parseInt( entrada.nextLine() ));
}
}
```
Aplicação antiga `AppCarro`
```java
public class AppCarro {
public static void main(String[] args) {
Carro car1 = new Carro();
car1.entradadeDados();
car1.imprimir();
Carro car2 = new Carro();
car2.entradadeDados();
car2.imprimir();
Carro car3 = new Carro();
car3.entradadeDados();
car3.imprimir();
}
}
```
A execução da aplicação não foi afetada pelas mudanças na classe porque foi criado o construtor vazio public Carro ( ) { } que garantiu a compatibilidade:
Aplicação usando diferentes construtores para criar os objetos: `AppCarro`
```java
public class AppCarroNovo{
public static void main(String[] args){
Carro car1 = new Carro();
car1.entradaDados();
car1.imprimir();
Carro car2 = new Carro("AAA1A00", 25000);
car2.imprimir();
Carro car3 = new Carro("Logan", "Azul", "ABC1E00", 32000);
car3.imprimir();
Carro car4 = new Carro("Audi", "A5", "Prata", "AUD0I00", 123000);
car4.imprimir();
Carro car5 = new Carro("Fiat", "Argo", "Verde", "ABB1I00", 42000, 5, 2018, 2019);
car5.imprimir();
}
}
```
> [!Note]
>
> 1. O primeiro método construtor criado foi o vazio, para garantir a compatibilidade com a aplicação antiga;
> 2. Foram incluídos mais quatro métodos construtores seguindo o conceito da sobrecarga de métodos;
> 3. Na nova aplicação, foram criados cinco diferentes objetos, cada um usando um construtor diferente;
> 4. Ambas as aplicações funcionaram apesar da alteração;
## [Java] Polimorfismo de sobrecarga e a evolução das classes

