0

Modulo Java Básico

#Java
Vinicius Almeida
Vinicius Almeida

Eae pessoal, tudo tranquilo com vocês? Espero que sim. Venho aqui trazer mais um resumo de conclusão de módulo, abordando o que eu aprendi nas aulas. Deixo aqui disponível este artigo para quem quiser revisar os conceitos abordados durante o módulo. Se eu ajudei você, não deixe de marcar o Artigo como útil.


O que precisamos sabe sobre Java


  • Java é uma linguagem de programação e plataforma computacional lançada em 1995 pela Sun Microsystems, por um time comandado por James Gosling. Diferente de outras linguagens de programação, que são compiladas para código nativo, o Java é compilado para um bytecode que é interpretado por uma máquina virtual Java, JVM.


  • Já um compilador é um programa que, a partir de um código fonte, cria um programa semanticamente equivalente, porém escrito em outra linguagem, código objeto. Um compilador traduz um programa de uma linguagem textual para uma linguagem de máquina, específica para um processador e sistema operacional.


  • O nome compilador é usado principalmente para os programas que traduzem o código fonte de uma linguagem de programação de alto nível para uma linguagem de programação de baixo nível (por exemplo, Assembly ou código de máquina).


  • Máquina Virtual
  • Uma Máquina Virtual, ou Virtual Machine, é um software que simula uma máquina física e consegue executar vários programas, gerenciar processos, memória e arquivos. Tudo isso faz parte de uma plataforma com memória, processador e outros recursos totalmente virtuais, sem dependência do hardware.
  • JVM
  • A JVM é uma máquina virtual que executa programas Java, executando os bytecodes em linguagem de máquina para cada sistema operacional. Com o Java, compilamos para a JVM, o bytecode será executado pela máquina virtual, e não diretamente pelo SO, assim, o software escrito em Java possui portabilidade para qualquer sistema operacional, porém, cada JVM deve ser construída para um SO específico.
  • JRE
  • JRE significa Java Runtime Envirnment, ou Ambiente de Execução do Java, é composto pela Java Virtual Machine (JVM), bibliotecas e APIs da linguagem Java e outros componentes para suporte da plataforma Java.
  • JDK
  • Java Development Kit (JDK), Kit de Desenvolvimento Java, é um conjunto de utilitários que permitem criar software para a plataforma Java. É composto pelo compilador Java, bibliotecas da linguagem, ferramentas e a JRE.
  • Java SE
  • Java Standard Edition (SE), é a distribuição mínima da plataforma de desenvolvimento de aplicações Java.
  • Java EE
  • Java Enterprise Edition, é uma extensão da Java SE que possui suporte a desenvolvimento de sistemas corporativos. Além do mínimo da plataforma, o Java EE possui diversas especificações de partes da infra estrutura de aplicações, como acesso a banco de dados, mensageria, serviços web, parser de arquivos e outras. Servidores de Aplicações JavaEE, sabem seguir essas especificações e implementar os recursos para os usuários.
  • Jakarta EE
  • Com a falta de investimento da Oracle no Java, ela cedeu todo o código, implementações e especificações do JavaEE para a Eclipse Foundation, mas como o nome JavaEE é uma marca registrada, foi escolhido o nome JakartaEE.
  • Agora a evolução da especificações e padrões do Java será feito sobre o nome JakartaEE, com compatibilidade com o JavEE.


Características da Linguagem

  • Nas aulas, fomos ensinados que a linguagem Java possui tipagem estática, o que significa que as variáveis devem ser declaradas antes de serem usadas, o que obrigatoriamente nos força a criar um nome e definir um tipo para esta variável. Basicamente existem dois agrupamentos de Tipos de dados, os Tipos Primitivos, Wrappers e Tipos não Primitivos.


  • Tipos Primitivos
  • Não aceitam valores nulos e se não forem inicializados com algum valor, por padrão eles possuem um valor default.


  • Wrappers
  • São objetos que representam os tipos primitivos e por serem objetos, podem ter valores nulos atribuídos. Um das grandes vantagens em se utilizar os Wrappers são os métodos pré-estabelecidos para cada Wrapper. Aqui também entram mais dois conceitos muito importantes que são o AutoBoxing e UnBoxing.
  • Obs: que todas as classes herdam de object.


  • AutoBoxing
  • Faz a conversão de um tipo primitivo para sua respectiva classe Wrapper
  • Wrapper Classes in Java - GeeksforGeeks


  • UnBoxing
  • Faz o contrário de AutoBoxing. Converte uma classe Wrapper em seu respectivo tipo primitivo.


  • Tipos não primitivos
  • São eles : String, Number, Object e qualquer outro objeto.


  • Tipagem forte e estática
  • Ter uma tipagem estática significa que os tipos das variáveis são verificadas em tempo de compilação.
  • ter uma tipagem forte significa que uma vez atribuído um tipo de uma variável, ela só aceitara dados do tipo atribuído.
  • Além disso o Java pode também trabalhar com inferência de valores através da palavra reservada var, onde o compilador simplesmente entende o tipo de dado que você está atribuindo a variável.
Estamos declarando a variavel como var e passando numeros inteiros na sua criação, o que faz a inferência que a variavel 'numero' será do tipo inteiro.
var numero = 12345;
  • Modificadores de Acesso
  • São responsáveis por habilitar ou não a visualização de métodos, classes e atributos para outras classes e programas. Eles fazem o controle de quem tem acesso ou não as informações de uma classe.
  • Nas aulas fomos apresentados aos modificadores : public, private, protected, default, abstract, static e final.
  • Public
  • Uma classe ou método com o modificador public pode ser acessado de qualquer lugar por qualquer entidade que possa visualizar a classe a que ela pertence.
  • Private
  • Os métodos e atributos da classe definidos como privados não podem ser acessados ou usados por nenhuma outra classe. Esses atributos e métodos também não podem ser visualizados pelas classes herdadas.
  • Protected
  • Torna o membro acessível às classes do mesmo pacote ou através de herança, seus membros herdados não são acessíveis a outras classes fora do pacote em que foram declarados.
  • Default
  • A classe e/ou seus membros são acessíveis somente por classes do mesmo pacote, na sua declaração não é definido nenhum tipo de modificador, sendo este identificado pelo compilador.
  • Abstract
  • Esse modificador não é aplicado nas variáveis, apenas em classes e métodos. Uma classe abstrata não pode ser instanciada. Se houver alguma declaração de um método como abstract (abstrato), a classe também deve ser marcada como abstract.
  • Static
  • É usado para a criação de uma variável que poderá ser acessada por todas as instâncias de objetos desta classe como uma variável comum, ou seja, a variável criada será a mesma em todas as instâncias e quando seu conteúdo é modificado numa das instâncias, a modificação ocorre em todas as demais. E nas declarações de métodos ajudam no acesso direto à classe, portanto não é necessários instanciar um objeto para acessar o método.
  • Final
  • Quando é aplicado na classe, não permite estender, nos métodos impede que o mesmo seja sobrescrito (overriding) na subclasse, e nos valores de variáveis não pode ser alterado depois que já tenha sido atribuído um valor.
  • Enums
  • Em Java, uma enum é um tipo no qual declaramos um conjunto de valores constantes pré-definidos. Basicamente é um dicionários de dados imutável, qual não é permitido a criação de novas instâncias e por isso seu construtor é sempre declarado como private. Por convenção, por serem objetos constantes e imutáveis (static final), os nomes são em MAIÚSCULOS.
  • Exemplo:
public enum TipoVeiculo{
  TERRESTRE,
  AQUATICO,
  AEREO
}


Características da Linguagem II

  • Strings
  • O tipo String possui alguns métodos muito usados, tais como os exemplos abaixo:
Para a String declarada para a variavel texto como abaixo, podemos chamar alguns métodos nativos do tipo:
var texto = new String(" Minha String ");
texto.charAt(n) = Pega o char na posição n da String.
texto.length() = Pega o tamanho da String.
texto.trim() = Retira os espaços das extremidades da String.
texto.toLowerCase() = Transforma todas as letras em minúsculas.
texto.toUpperCase() = Transforma todas as letras em maiúsculas.
texto.contains("M") = Retorna TRUE se existir a String "M" dentro da string texto e FALSE se ela não existir.
texto.replace("n", "$") = Para cada "n" encontrado na String, ele será substituído por "$".
texto.equals(" Minha String ") = Retorna TRUE se a String contida dentro de texto for igual a " Minha String ".
texto.equalsIgnoreCase(" minha sTrinG ") = Faz a mesma função do equal de cima, porém será ignorado as diferenças entre letras maiúsculas e minúsculas.
texto.substring(1, 6) = Pega tudo o que está entre a posição 1 até a 6 da String texto.
  • String Format
  • Podemos concatenar Strings de várias formas como no exemplo abaixo:
var nome = "André";
var sobreNome = "Gomes";
​
*Concatenação com '+'
final var nomeCompleto = nome + sobreNome;
​
System.out.println(nome);
System.out.println("Nome do cliente : " + nome);
System.out.println("Nome completo do cliente : " + nomeCompleto);
​
*Podemos também usar interpolação com String.format() e colocar %s onde queremos substituir por uma variável como no exemplo abaixo. Lembrando que as variáveis serão chamadas em ordem.
final var mensagem = String.format("O cliente %s possui sobre nome %s ", nome, sobreNome);
​
*Podemos também formatar a saida de casas decimais de uma String.
System.out.println(String.format("Numero %.2f ", 1.2375d));
  • String Builder
  • O Java possui uma Classe especial para facilitar e tornar mais eficiente a concatenação de Strings que faz parte da biblioteca java.lang, essa classe se chama String Builder. Para usarmos suas funções devemos declarar a classe como no exemplo abaixo:
*eclaração do StringBuilder
var builder = new StringBuilder();
​
*Estou fazendo a concatenação da String "Luis dentro de builder.
builder.append("Luis ");
*Estou fazendo a concatenação da String "Otavio" dentro de builder.
builder.append("Otavio");
​
*Imprime o coteúdo de nosso StringBuilder.
System.out.println(builder);
*Resultado = "Luis Otávio"
​
*Escreve o conteúdo do StringBuilder de traz para frente.
final var reverse = builder.reverse();
​
*Insere um "#" na posição 0 do StringBuilder reverse.
reverse.insert(0, "#");
  • Laços, Condicionais e Operadores
  • Dentro do Java possuímos alguns laços de repetição como : for, While, Do While e etc. Condicionais como IF e o IF ternário.


  • Condicional IF e Else
  • IF é uma palavra reservada do java que remete ao uso de condições no código. Caso a condição não seja verdadeira, é executado o código dentro do corpo do Else.
  • Exemplo:
if (condicao) {
   System.out.println("A condição é verdadeira");
 } else {
   System.out.println("A condição é falsa");
 }
  • É também possível utilizar o If de forma ternária como no exemplo abaixo:
var ternario = condicao ? "é verdadeira" : "é falsa";
​
*Primeiro testamos a condição. Se ela for verdadeira é executado o que está entre os caracteres especiais '? e :', caso o contrário, é executado o que está após ':'


  • Operadores
  • Os operadores podem ser de atribuição, aritméticos, relacionais, de igualdade, lógicos, de incremento ou decremento.
  • Atribuição
  • O operador de atribuição é utilizado para definir o valor inicial ou sobrescrever o valor de uma variável.
  • Aritméticos
  • Os operadores aritméticos realizam as operações fundamentais da matemática entre duas variáveis e retornam o resultado.
  • Incremento e Decremento
  • Para incrementar usamos o ++ e para decrementas usamos o --. O incremento/decremento pode ser usado antes ou depois de uma variável, o que muda o seu funcionamento. Se usado antes da variável, o incremento/decremento será feito imediatamente quando o compilador chegar naquela linha de código. Se usado depois da variável, o incremento/decremento será feito assim que o compilador passar por aquela linha de código.
  • Exemplo:
int numero = 5;
​
*Incremento antes
++numero;
​
*Decremento depois
numero--;
  • Relacionais
  • Fazem relação entre dois valores.
  • Igualdade
  • Verificam se dois valores são iguais ou diferentes.
  • Lógicos
  • Nos permite fazer a conjectura de duas ou mais expressões, sendo elas do tipo Sort Circuit ou Non Sort Circuit.
  • Non Sort Circuit
  • Se a primeira expressão for falsa, o código não irá verificar a segunda. É o tipo de expressão mais comum e mais performática.
  • Sort Circuit
  • Irá verificar todas as condições da conjectura. As vezes se faz necessário que todas as expressões sejam executadas. Aqui utilizamos apenas um '&' como operador lógico 'E', também utilizamos apenas um '|' como operador lógico 'OU'.


  • Laços de Repetição
  • Laço For
  • A estrutura de repetição "for", ou então, laço de repetição, iterador é a estrutura mais utilizada quando precisamos executar diversas vezes um mesmo bloco de código. Um for precisa de três informações básicas em sua declaração: for(info1; info2; info3){}
  • Onde:
  • info1 é a parte onde se declara uma variável e seu valor inicial(geralmente i=0).
  • info2 é onde se declara até onde deve ir a iteração.
  • info3 é a parte do incremento da variável.
  • Exemplo:
​
for (int i = 0; i <= 10; i = i + 1) {
   System.out.println("I=" + i);
 }
  • While
  • É uma estrutura que executará o código contido em seu corpo enquanto sua condição for verdadeira.
  • Exemplo:
var x = 0;
while (x < 1) {
   System.out.println("Dentro do while...");
   x++;
}
  • Do While
  • Muito semelhante a condição de cima, porém o Do While irá executar os comandos primeiro para depois fazer a verificação, além de o incremento poder ser feito dentro de sua condição. Por causa deste comportamento, este laço sempre será executado pelo menos uma vez.
  • Exemplo:
var y = 0;
do {
 System.out.println("Dentro do do/while...");
} while (y++ < 1);
  • Convenções de Nomes
  • O padrão no Java é o Cammel Case.
  • Nomes de Classes:
  • Para nomearmos uma classe em Java devemos seguir as seguintes regras:
  • Toda classe deve começar com letra Maiúscula.
  • Não deve possuir caracteres com acento (ç, á, î, ã, Á, À).
  • Não deve possuir caracteres especias (@, !, %, &).
  • Caso um classe possua um nome composto, a primeira letra de cada palavra deverá começar com letra maiúscula.
  • Nomes de Métodos
  • Métodos (funções) podem começar com qualquer letra minúscula, não podem possuir acentos e não podem começar com números. Caso o nome de um método seja composto por mais de uma palavra, a primeira letra da segunda palavra e das palavras posteriores deve ser em maiúscula.
  • Nomes de Variáveis
  • Usar nomes mais sucintos. Sempre minúsculos e de preferência, não usar números em sua composição.
  • Code Style Plugins
  • Checkstyle Gradle Plugin - Plugin para verificar checks do código.
  • Manual do Plugin.


  • PMD Gradle Plugin - Plugin para fazer analisar mais profunda no código.
  • Manual do Plugin.
  • Para adicionar os plugins no projeto precisamos editar o arquivo build.gradle. Devemos adicionar ao código de plugins os valores:
  • Para Checkstyle Gradle: id 'checkstyle'
  • Para PMD Gradle: id 'pmd'
*Aqui estamos habilitando os dois plugins.
plugins {
  id 'java'
  id 'checkstyle'
  id 'pmd'
}
  • E depois devemos adicionar as configurações dos plugins:
Para CheckStyle:
*toolVersion = (colocar a versão mais atual do site)
*configFile = (caminho do arquivo xml do plugin baixado)
​
checkstyle {
  toolVersion = '8.21'
  showViolations = true
  configFile = file("config/checkstyle/checkstyle.xml")
}
​
Para PMD:
*ruleSetFiles = (caminho do arquivo xml do plugin baixado)
*toolVersion = (colocar a versão mais atual do site)
​
pmd {
  //ruleSets = ["category/java/errorprone.xml", "category/java/bestpractices.xml"]
  ruleSetFiles = files("config/pmd/ruleset.xml")
  toolVersion = '6.15.0'
  ignoreFailures = true
  consoleOutput = true
}


Debug Código

Para debugar um código através do inteliJ, o primeiro passo é colocar um BreakPoint(ponto de quebra) no código. Fazemos isso clicando entre o número da linha e o código, bem onde está a bolinha vermelha.

Ao rodar o modo debug, a execução ira parar e esperar quando chegar neste ponto do código. Para prosseguir para o próximo BreakPoint, clicamos no botão Resume e enquanto o código não passar em mais nenhum BreakPoint, o programa continuará rodando normalmente. Além do resume, podemos fazer outras operações como:

  • Opção Step-Over que faz o debug linha a linha.
  • Opção Step-Int que entra dentro de algum método.
  • Opção Step-Out que sai de algum método.
  • Opção Evaluete que executa um código sem precisar executar a sua linha.


Orientação à Objetos com Java

  • Segundo Robert Martin, o "Uncle Bob" , "A programação Orientada a Objetos impõe disciplina sobre a transferência indireta do Controle".
  • O que são Classes?
  • Uma classe vai funcionar como uma espécie de molde que nos servirá como base para construir algo. Quando pensamos em construir uma casa, nós fazemos uma planta baixa. Ela será o modelo que utilizaremos para construir algo concreto. As classes funcionam de forma parecida.
  • Exemplo de declaração de classe:
public class Pessoa {
 //Atributo da classe
 private String nome = "Marco";
 //metodo da classe
 public String getNome() {
   return nome;
 }
 //metodo da classe
 public String falarMeuProprioNome(){
   return "Olá, meu nome é " + getNome();
 }
 //metodo da classe
 public String andar() {
   return "Andando...";
 }
}
  • O que são objetos?
  • Agora que entendemos que temos um modelo que podemos seguir, O que podemos fazer com esse modelo? Bom.. Nós fizemos a analogia da casa, certo ? Depois de termos a planta baixa, nós começamos a construir. E o resultado do que nós construímos, vamos chamar de objeto.
  • Quando nós utilizamos a nossa classe Pessoa - mostrada no código anterior - para criar um objeto, nós diremos que estamos instanciando um objeto da classe Pessoa.
  • E esse termo é bem simples de entender. O que acontece é que podemos criar vários objetos de uma mesma classe, ou seja, várias instâncias de objetos.
public static void main(String[] args) {
​
 Pessoa pessoa = new Pessoa();
​
 System.out.println(pessoa.getNome());
 // Marco
​
}
  • O que são Atributos?
  • Agora vamos pensar no que nos definimos como nome na classe Pessoa. Foi tão intuitivo nós pensarmos que uma pessoa teria um nome que nem demos importância a ele. O nome é uma característica de uma Pessoa e pode ser diferente de pessoa para pessoa. O nome é um atributo da pessoa.
  • O que são Métodos?
  • Agora vamos pensar que uma pessoa pode ter ações. Por exemplo, uma pessoa pode falar.
  • Pensando em um cenário mais específico, uma pessoa pode falar o seu nome.
  • As ações que nós definimos que uma classe pode ter, nós chamamos de métodos. Estes metodos já foram definidos dentro da classe Pessoa.
  • Construtores
  • Podemos entender o termo construtor no sentido literal, afinal vamos construir um objeto.
  • Por meio de um construtor, criamos um objeto baseado em uma Classe e assim o alocamos em memória. Ao criarmos um objeto dizemos que estamos instanciando um objeto.
  • Esse exemplo que acabamos de ver é o exemplo mais comum quando começamos a estudar construtores em Java. E para instanciar essa classe (criar um objeto dela) fazemos o seguinte: Pessoa pessoa = new Pessoa();
  • Também podemos criar construtores parametrizados. Dessa forma, conseguimos definir um contrato onde sempre será obrigatório passar alguma informação na hora de instanciar a classe.
  • No exemplo abaixo temos dois construtores. Um com passagem de parâmetro e outro sem. Isso garante que possamos instanciar duas duas maneiras.
  • Exemplo de definição de um Construtor:
public class Pessoa {
 private String nome;
  
 //Construtor padrão
 public Pessoa() {    
 }
  
 //construtor com parâmetros
 public Pessoa(String nome) {
   this.nome = nome;
 }
​
}
  • Encapsulamento
  • Mais uma vez vamos entender o termo que estamos trabalhando ao pé da letra.
  • Quando falamos de encapsulamento, estamos falando efetivamente em proteger alguma informação de alguma forma, ou seja, com uma cápsula.
  • Queremos garantir a nossa implementação e que o acesso a determinados dados estão realmente protegidos do acesso externo.
  • Exemplo:
public class Pessoa {
 //Como os atributos são private, eles ficam inacessiveis pelo objeto.
 private String nome;
 private LocalDate dataNascimento;
​
 //A instanciação da classe obriga a inserção destes atribuitos.
 public Pessoa(String nome, int dia, int mes, int ano) {
   this.nome = nome;
   this.dataNascimento = LocalDate.of(ano, mes, dia);
 }
​
 public int calculaIdade(){
   return Period.between(dataNascimento, LocalDate.now()).getYears();
 }
 
 //O acesso ao nome dentro do objeto só é possivel pela chamada do metodo   //getNome()
 public String getNome() {
   return nome;
 }
 //O acesso a data de Nascimento dentro do objeto só é possivel pela chamada do   //metodo getDataNascimento()
 public LocalDate getDataNascimento() {
   return dataNascimento;
 }
​
 //O nome é o único atributo que pode ser alterado, justamente porque existe um   //método para isso.
 public void setNome(String nome) {
   this.nome = nome;
 }
}
  • Herança e Polimorfismo
  • Vamos agora falar de outro pilar importante da Orientação Objetos: a Herança. Como o próprio nome já diz, essa é a capacidade de uma Classe herdar o comportamento de outra.
  • Exemplo:
  • Vamos pensar em um cenário onde queremos informações de diversos tipos de veículos.
  • Por exemplo: quero colocar a quantidade de portas para o caso de carros e as cilindradas em casos de motocicletas. Quando usamos a palavra reservada extends, estamos dizendo que nossa classe herda de alguém. No exemplo abaixo, dizemos que a classe Carro extends Veiculo. Ou seja, a classe Carro herda todos os atributos e métodos da Classe Veiculo. Portanto dizemos que Carro é um Veiculo. Quando falamos em herança, o verbo ser é mandatório na nossa forma de falar sobre a classe. Aqui é onde entraria o Polimorfismo. Ele nos garantirá a capacidade de um objeto ser referenciado de múltiplas formas. O Java será capaz de identificar qual objeto foi instanciado e, assim, escolher qual método será utilizado.
//Classe para Veículos
public class Veiculo {
​
 private String modelo;
 private String marca;
​
 public String getModelo() {
   return modelo;
 }
​
 public void setModelo(String modelo) {
   this.modelo = modelo;
 }
​
 public String getMarca() {
   return marca;
 }
​
 public void setMarca(String marca) {
   this.marca = marca;
 }
​
 public void acelera() {
   System.out.println("Acelerando...");
 }
​
}
​
//Classe para Carros
public class Carro extends Veiculo {
​
 private int quantidadeDePortas;
​
 public int getQuantidadeDePortas() {
   return quantidadeDePortas;
 }
​
 public void setQuantidadeDePortas(int quantidadeDePortas) {
   this.quantidadeDePortas = quantidadeDePortas;
 }
}
​
// Classe para Motos
public class Motocicleta extends Veiculo {
​
 private String cilindradas;
​
 public String getCilindradas() {
   return cilindradas;
 }
​
 public void setCilindradas(String cilindradas) {
   this.cilindradas = cilindradas;
 }
}
​
 public static void main(String[] args) {
  
  //Carro é um veículo
   Veiculo carro = new Carro();
   carro.acelera();
​
  //Moto também é um veiculo
   Veiculo moto = new Motocicleta();
   moto.acelera();
​
 }
  • This
  • Quando estamos trabalhando com o termo this, no Java, estamos, na verdade, fazendo uma auto referência. No exemplo abaixo, como o atributo quantidadeDePortas e o parâmetro do construtor da classe tem o mesmo nome, o compilador precisa saber quem é quem e ele faz isso através da palavra this.
public class Carro extends Veiculo {
​
 private int quantidadeDePortas;
​
 public void setQuantidadeDePortas(int quantidadeDePortas) {
   this.quantidadeDePortas = quantidadeDePortas;
 }
 
}
  • Super
  • Analogamente ao This, quando falamos no Super, também estamos fazendo uma referência, mas dessa vez estamos fazendo referência a superclasse em um cenário de herança.
  • Primeiro vamos transformar a nossa classe veículo. Ela vai passar a ser uma classe abstrata e, portanto, não poderá mais ser instanciada. E também vamos definir que o construtor dessa classe sempre irá esperar o modelo, a marca e o valor venal.
public abstract class Veiculo {
​
 private String modelo;
 private String marca;
​
 private double valorVenal;
​
 public Veiculo(String modelo, String marca, double valorVenal) {
   this.modelo = modelo;
   this.marca = marca;
   this.valorVenal = valorVenal;
 }
​
 public String getModelo() {
   return modelo;
 }
​
 public void setModelo(String modelo) {
   this.modelo = modelo;
 }
  
//Sendo assim quando formos declarar nosso construtor na classe Carro que herda de //veiculo, podemos usar a palavra super para facilitar nossa vida:
//Não precisamos referênciar os atributos pois eles já foram referenciados na //classe Veiculo
public class Carro extends Veiculo {
​
 public Carro(String modelo, String marca, double valorVenal) {
   super(modelo, marca, valorVenal);
 }
​
 public Carro(String modelo, String marca, double valorVenal, int quantidadeDePortas) {
   super(modelo, marca, valorVenal);
   this.quantidadeDePortas = quantidadeDePortas;
 }
​
  • Obs : Como em Java, todas as nossas classes herdam de Object, se usamos o super em uma classe que não tem um extends explícito, estamos fazendo referência ao Object.
  • Equals
  • Como sabemos, todas as classes em Java herdam de Object. E, portanto, tem por padrão alguns métodos. Um deles é o equals que serve para fazer comparações entre objetos. Entretanto esse método possui algumas peculiaridades. Por padrão, quando estamos comparando dois objetos, estamos comparando a referência deles. Então se instanciarmos dois carros, por mais que eles tenham exatamente as mesmas informações, o Java não é capaz de identificar.
  • Mas poderíamos sobrescrever o método equals() para que nossa lógica funcione do jeito que gostaríamos. Tenha em mente que é uma boa prática sobrescrever este método.
  • Exemplo: Definimos a tag @Override e sobrescrevemos o método equals para que se a marca, modelo e valor venal dos objetos comparados forem iguais, então os dois objetos são iguais.
public abstract class Veiculo {
​
  private String modelo;
  private String marca;
  private double valorVenal;
​
  public Veiculo(String modelo, String marca, double valorVenal) {
    this.modelo = modelo;
    this.marca = marca;
    this.valorVenal = valorVenal;
 }
​
  @Override
  public boolean equals(Object obj) {
    if (obj == null) {
      return false;
   }
​
    Veiculo comparavel;
    if (obj instanceof Veiculo) {
      comparavel = (Veiculo)obj;
   } else {
      return false;
   }
​
    if (comparavel.marca == this.marca && comparavel.modelo == this.modelo && comparavel.valorVenal == this.valorVenal) {
      return true;
   }
​
    return false;
 }
​
}
  • HashCode
  • Quando falamos em hashCode, precisamos pensar em um código gerado que garanta um caráter único ao nosso objeto. Essa pode ser uma forma muito interessante para que possamos comparar se realmente um objeto é igual ao outro.
  • Semelhante ao exemplo anterior, declaramos a tag @Override e sobrescrevemos o metodo hashCode(), o qual cria um hash para os atributos modelo, marca e valorVenal. O que torna muito mais fácil de saber se os objetos são iguais, pois agora podemos apenas comparar os hashs dos objetos.
public abstract class Veiculo {
​
  private String modelo;
  private String marca;
  private double valorVenal;
​
  public Veiculo(String modelo, String marca, double valorVenal) {
    this.modelo = modelo;
    this.marca = marca;
    this.valorVenal = valorVenal;
 }
@Override
  public int hashCode() {
    return Objects.hash(modelo, marca, valorVenal);
 }
}


Aprenda sobre SOLID com Java

SOLID -> É um acrônimo dos princípios da programação orientada a objeto descritos por Robert C. Martin(Uncle Bob). Estes princípios auxiliam o programador a escrever códigos limpos, facilitando a refatoração e estimulando o reaproveitamento de código.

  1. SRP = Single Responsibility Principle
  2. "Uma Classe deve ter um e somente um motivo para mudar". A classe deve ter somente um único objetivo dentro do Software.
  3. Se a classe tiver outras funções atribuídas, deve-se então criar classes separadas para cada outra função.
  4. OCP = Open-Closed Principle
  5. "Você deve poder estender um comportamento de classe, sem modificá-lo".
  6. -Objetos devem estar abertos para extensão, mas fechados para modificação. Como ? Através do uso da abstração com interfaces.
  7. -Quando novos comportamentos precisam ser adicionados no software, devemos estender e não alterar o código fonte original.
  8. LSP = Liskov Substitution Principle
  9. "Classes derivadas devem ser substituíveis por suas classes base"
  10. -Este princípio diz que se uma Classe pai tiver alguma implementação que não faz sentido para a Classe filha, esta Classe deve ser repensada. "Cuidado com as abstrações".
  11. ISP = Interface Segregation Principle
  12. "Faça interfaces refinadas que são específicas do cliente".
  13. -Uma classe não deve ser forçada a implementar interfaces e métodos que não serão utilizados.
  14. DIP = Dependency Inversion Principle
  15. "Dependa de abstrações e não de implementações"
  16. Um módulo de alto nível não deve depender de módulos de baixo nível. Ambos devem depender da abstração.

Exemplo:

public interface ILeitorArquivo {
 void Ler(final String arquivo);
}
​
public class LeitorTxt implements ILeitorArquivo{
​
 @Override
 public void Ler(String arquivo) {
   //implementação
 }
}
​
public class Test{
 private final ILeitorArquivo leitor;
​
 public Test(ILeitorArquivo leitor) {
   this.leitor = leitor;
 }
​
 public void ler(){
   leitor.Ler("C:\\temp\\teste.txt");
 }
}


Trabalhando com Datas

*Usam o import java.util.Date;

Date() -> Inicia um construtor com o milissegundo mais próximo

Date(long date) -> Espera como parâmetro os milissegundos em formato long.

*Epoch = Padrão altamente aceito para representar uma data como um inteiro 32-bits a partir do início do Unix Epoch(1 de janeiro de 1970 00:00:00)


Instant : Marca um ponto no tempo

  1. Classe Calendar : É uma classe abstrata que provê métodos para converter datas entre um instante específico.
  2. *Usa o pacote java.util.Calendar
  3. -Ex Calendar agora = Calendar.getinstance(); -> possui diversas informações sobre a data como as da imagem abaixo: